Mkyong-中文博客翻译-三-

Mkyong 中文博客翻译(三)

原文:Mkyong

协议:CC BY-NC-SA 4.0

如何在 Java 中格式化 FileTime

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

在 Java 中,我们可以使用DateTimeFormatterFileTime转换成其他自定义的日期格式。

 public static String formatDateTime(FileTime fileTime) {

        LocalDateTime localDateTime = fileTime
                .toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();

        return localDateTime.format(
              DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss"));
} 

1.文件上次修改时间

此示例以自定义日期格式显示文件的上次修改时间。

GetLastModifiedTime.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.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

public class GetLastModifiedTime {

    private static final DateTimeFormatter DATE_FORMATTER =
            DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss");

    public static void main(String[] args) {

        String fileName = "/home/mkyong/test";

        try {

            Path file = Paths.get(fileName);
            BasicFileAttributes attr =
                    Files.readAttributes(file, BasicFileAttributes.class);

            // default YYYY-MM-DDThh:mm:ss[.s+]Z
            System.out.println("lastModifiedTime: " + attr.lastModifiedTime());

            FileTime fileTime = attr.lastModifiedTime();
            System.out.println("lastModifiedTime: " + formatDateTime(fileTime));

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static String formatDateTime(FileTime fileTime) {

        LocalDateTime localDateTime = fileTime
                .toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();

        return localDateTime.format(DATE_FORMATTER);
    }

} 

输出

 lastModifiedTime: 2020-07-20T09:29:54.627222Z

lastModifiedTime: 07/20/2020 17:29:54 

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-io

参考

如何用 Hibernate 工具生成 Hibernate 映射文件和注释

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/how-to-generate-code-with-hibernate-tools/

在本文中,我们将向您展示如何使用 Hibernate / JBoss Tools 从数据库自动生成 Hibernate 映射文件(hbm)和注释代码。

本文中的工具

  1. Eclipse v3.6 (Helios)
  2. JBoss / Hibernate 工具 3.2 版
  3. Oracle 11g
  4. JDK 1.6

Note
Before proceed, please Install Hibernate / JBoss Tools in Eclipse IDE.

1.Hibernate 透视图

打开你的休眠视角。在 Eclipse IDE 中,选择“Windows”>>打开透视图>>其他… ,选择“休眠”。

2.新的休眠配置

在 Hibernate 透视图中,右键选择“添加配置…

在“编辑配置”对话框中,

  1. 项目框中,点击【浏览..】按钮选择您的项目。
  2. 在“数据库连接框中,点击“新建..”按钮来创建数据库设置。
  3. 配置文件框中,点击【设置】按钮创建一个新的或者使用已有的【休眠配置文件】,hibernate.cfg.xml

Eclipse Hibernate Tools

在“ Hibernate 透视图”中查看您的表列表。

Eclipse Hibernate Tools

hibernate.cfg.xml”示例,连接到 Oracle 11g 数据库。

 <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
  <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
  <property name="hibernate.connection.url">jdbc:oracle:thin:@127.0.0.1:1521:MKYONG</property>
  <property name="hibernate.connection.username">mkyong</property>
  <property name="hibernate.connection.password">password</property>
  <property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property>
  <property name="hibernate.default_schema">MKYONG</property>
 </session-factory>
</hibernate-configuration> 

3.Hibernate 代码生成

现在,您已经准备好生成 Hibernate 映射文件和注释代码了。

–在“Hibernate 透视图”中,点击“ Hibernate 代码生成”图标(见下图),选择“Hibernate 代码生成配置”

Hibernate Code Generation

–创建一个新配置,选择您的“控制台配置”(在步骤 2 中配置),放置您的“输出目录,选中选项“从 JDBC 连接反向工程”。

Hibernate Code Generation

–在“ Exporter 选项卡中,选择要生成的内容、模型、映射文件(hbm)、DAO、注释代码等。

Hibernate Code Generation

看到结果

Hibernate Code GenerationNote
The generated Hibernate mapping file and annotations code are very clean, standard and easy to modify. Try explore more features.

如何在 Java 中获得当前时间戳

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-get-current-timestamps-in-java/

本文展示了几个用 Java 获取当前日期时间或时间戳的 Java 示例。(Java 8 更新)。

代码片段

 // 2021-03-24 16:48:05.591
  Timestamp timestamp = new Timestamp(System.currentTimeMillis());

  // 2021-03-24 16:48:05.591
  Date date = new Date();
  Timestamp timestamp2 = new Timestamp(date.getTime());

  // convert Instant to Timestamp
  Timestamp ts = Timestamp.from(Instant.now())

  // convert ZonedDateTime to Instant to Timestamp
  Timestamp ts = Timestamp.from(ZonedDateTime.now().toInstant()));

  // convert Timestamp to Instant
  Instant instant = ts.toInstant(); 

目录

1。Java 时间戳示例

下面的程序使用java.sql.Timestamp获取当前时间戳,并用SimpleDateFormat格式化显示。

TimeStampExample.java

 package com.mkyong.app;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;

public class TimeStampExample {

    // 2021.03.24.16.34.26
    private static final SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss");

    // 2021-03-24T16:44:39.083+08:00
    private static final SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");

    // 2021-03-24 16:48:05
    private static final SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args) {

        // method 1
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        System.out.println(timestamp);                      // 2021-03-24 16:34:26.666

        // method 2 - via Date
        Date date = new Date();
        System.out.println(new Timestamp(date.getTime()));  // 2021-03-24 16:34:26.666
                                                            // number of milliseconds since January 1, 1970, 00:00:00 GMT
        System.out.println(timestamp.getTime());            // 1616574866666

        System.out.println(sdf1.format(timestamp));         // 2021.03.24.16.34.26

        System.out.println(sdf2.format(timestamp));         // 2021-03-24T16:48:05.591+08:00

        System.out.println(sdf3.format(timestamp));         // 2021-03-24 16:48:05

    }
} 

输出

Terminal

 2021-03-24 16:48:05.591
2021-03-24 16:48:05.591
1616575685591
2021.03.24.16.48.05
2021-03-24T16:48:05.591+08:00
2021-03-24 16:48:05 

2。将时间转换为时间戳/从时间戳转换为时间

这个例子展示了如何在新的 Java 8 java.time.Instant和旧的java.sql.Timestamp之间进行转换。

 // convert Instant to Timestamp
  Timestamp ts = Timestamp.from(Instant.now())

  // convert Timestamp to Instant
  Instant instant = ts.toInstant(); 

InstantExample.java

 package com.mkyong.app;

import java.sql.Timestamp;
import java.time.Instant;

public class InstantExample {

  public static void main(String[] args) {

      Timestamp timestamp = new Timestamp(System.currentTimeMillis());
      System.out.println(timestamp);                  // 2021-03-24 17:12:03.311
      System.out.println(timestamp.getTime());        // 1616577123311

      // Convert Timestamp to Instant
      Instant instant = timestamp.toInstant();
      System.out.println(instant);                    // 2021-03-24T09:12:03.311Z
      System.out.println(instant.toEpochMilli());     // 1616577123311

      // Convert Instant to Timestamp
      Timestamp tsFromInstant = Timestamp.from(instant);
      System.out.println(tsFromInstant.getTime());    // 1616577123311
  }
} 

输出

Terminal

 2021-03-24 17:12:03.311
1616577123311
2021-03-24T09:12:03.311Z
1616577123311
1616577123311 

3。将时间戳插入表中

java.sql.Timestamp在 JDBC 编程中仍被广泛使用。请参见下面的转换:

 // Java 8, java.time.*

  // convert LocalDateTime to Timestamp
  preparedStatement.setTimestamp(1, Timestamp.valueOf(LocalDateTime.now()));

  // convert Instant to Timestamp
  preparedStatement.setTimestamp(1, Timestamp.from(Instant.now()));

  // Convert ZonedDateTime to Instant to Timestamp
  preparedStatement.setTimestamp(3, Timestamp.from(ZonedDateTime.now().toInstant())); 

下面的例子是在表格中插入一个Timestamp的 JDBC 例子。

JdbcExample.java

 package com.mkyong.app;

import java.math.BigDecimal;
import java.sql.*;
import java.time.LocalDateTime;

public class JdbcExample {

  private static final String SQL_INSERT = "INSERT INTO EMPLOYEE (NAME, SALARY, CREATED_DATE) VALUES (?,?,?)";

  public static void main(String[] args) {

      try (Connection conn = DriverManager.getConnection(
              "jdbc:postgresql://127.0.0.1:5432/test", "postgres", "password");
           PreparedStatement preparedStatement = conn.prepareStatement(SQL_INSERT)) {

          preparedStatement.setString(1, "mkyong");
          preparedStatement.setBigDecimal(2, new BigDecimal("799.88"));
          preparedStatement.setTimestamp(3, Timestamp.valueOf(LocalDateTime.now()));

          // preparedStatement.setTimestamp(3, Timestamp.from(ZonedDateTime.now().toInstant()));
          // preparedStatement.setTimestamp(3, Timestamp.from(Instant.now()));

          int row = preparedStatement.executeUpdate();

          // rows affected
          System.out.println(row); //1

      } catch (SQLException e) {
          System.err.format("SQL State: %s\n%s", e.getSQLState(), e.getMessage());
      } catch (Exception e) {
          e.printStackTrace();
      }

  }
} 


更多例子为用 Java 获取当前日期时间或时间戳。

4。参考文献

如何用 jQuery 和 JSON 获得好吃的书签计数

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jquery/how-to-get-delicious-bookmark-count-with-jquery-and-json/

最好的书签网站 Delicious ,提供了许多 API 让开发者处理书签的数据。下面是一个使用 jQuery 检索给定 URL 的书签总数的例子。

美味 API

要获得书签总数,请使用以下命令

 http://feeds.delicious.com/v2/json/urlinfo/data?url=xxx.com&callback=? 

jQuery Ajax

jQuery 附带了一个简单而强大的。ajax() 或简写。getJSON() 按需获取远程数据。

1.jQuery。ajax()示例

使用 jQuery 。ajax() 从 Delicious 获取 json 数据,并显示书签计数的总数。

 $.ajax({ 
 type: "GET",
 dataType: "json",
 url: "http://feeds.delicious.com/v2/json/urlinfo/data?url="+url+"&amp;callback=?",
 success: function(data){			
	var count = 0;
	if (data.length > 0) {
		count = data[0].total_posts;
	}
	$("#delicious_result").text(count + ' Saved');			
 }
 }); 
2.jQuery。getJSON()示例

以上的简写。ajax() 方法,两者都在做同样的任务。

 $.getJSON("
   http://feeds.delicious.com/v2/json/urlinfo/data?url="+url+"&callback=?",

   function(data) {

   var count = 0;
   if (data.length > 0) {
	count = data[0].total_posts;
   }
   $("#delicious_result").text(count + ' Saved');

}); 

你自己试试

在本例中,在文本框中输入 URL,然后点击按钮以获得 Delicious 中书签的总数。

 <html>
<head>
<script type="text/javascript" src="jquery-1.4.2.min.js"></script>
</head>

<body>
<h1>Get Delicious bookmark count with jQuery</h1>

URL : <input type='text' id='url' size='50' value='http://www.google.com' />
<br/><br/>
<h2>Delicious count : <span id="delicious_result"></span></h2>

<button id="delicious">Get Delicious Count (.Ajax)</button>
<button id="delicious2">Get Delicious Count (.getJSON)</button>
<script type="text/javascript">

$('#delicious').click(function(){

 $("#delicious_result").text("Loading......");

 var url = $('#url').val();

 $.ajax({ 
 type: "GET",
 dataType: "json",
 url: "http://feeds.delicious.com/v2/json/urlinfo/data?url="+url+"&amp;callback=?",
 success: function(data){

	var count = 0;
	if (data.length > 0) {
		count = data[0].total_posts;
	}
	$("#delicious_result").text(count + ' Saved');

   }
  });
});

$('#delicious2').click(function(){

 $("#delicious_result").text("Loading......");

 var url = $('#url').val();

 $.getJSON("
    http://feeds.delicious.com/v2/json/urlinfo/data?url="+url+"&callback=?",

 function(data) {

	var count = 0;
	if (data.length > 0) {
		count = data[0].total_posts;
	}
	$("#delicious_result").text(count + ' Saved');

  });	
});
</script>

</body>
</html> 

http://web.archive.org/web/20220204001715if_/https://www.mkyong.com/wp-content/uploads/jQuery/jQuery-get-delicious-bookmark-count-example.html

Try Demo

参考

  1. http://delicious.com/help/feeds
  2. http://API . jquery . com/jquery . getjson/

如何在 Java 中获取文件扩展名

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

本文展示了如何在 Java 中获取文件的文件扩展名。

主题

  1. 获取文件扩展名正常
  2. 获取文件扩展名严格
  3. 获取文件扩展名硬编码
  4. Apache 通用 IO–filename utils
 Path: /path/foo.txt                  -> File Extension: txt
  Path: .                              -> File Extension:
  Path: ..                             -> File Extension:
  Path: /path/run.exe                  -> File Extension: exe
  Path: /path/makefile                 -> File Extension:
  Path: /path/.htaccess                -> File Extension: htaccess
  Path: /path/.tar.gz                  -> File Extension: gz
  Path: /path/../makefile              -> File Extension:
  Path: /path/dir.test/makefile        -> File Extension: 

查看上面从获取文件扩展名严格示例的输出。对于没有扩展名的文件,我们将显示为空。

1。获取文件扩展名,普通版本。

这个例子展示了如何使用 String#lastIndexOf 来获取文件的文件扩展名,它应该适合大多数情况。

 String extension = "";

  int index = fileName.lastIndexOf('.');
  if (index > 0) {
      extension = fileName.substring(index + 1);
  } 

但是,对于以下情况,上述方法将失败:目录名或文件路径包含一个点或双点,并且文件没有扩展名。

 Path: /path/../makefile              -> File Extension: /makefile
  Path: /path/dir.test/makefile        -> File Extension: test/makefile 

完整的例子。

GetFileExtension1.java

 package com.mkyong.io.howto;

public class GetFileExtension1 {

    private static final String OUTPUT_FORMAT = "Path: %-30s -> File Extension: %s";

    public static void main(String[] args) {

        String[] files = {
                "/path/foo.txt",
                ".",
                "..",
                "/path/run.exe",
                "/path/makefile",
                "/path/.htaccess",
                "/path/.tar.gz",
                "/path/../makefile",
                "/path/dir.test/makefile"
        };

        for (String file : files) {
            String output = String.format(OUTPUT_FORMAT, file, getFileExtension(file));
            System.out.println(output);
        }

    }

    /**
     * Fail for below cases
     * <p>
     * "/path/../makefile",
     * "/path/dir.test/makefile"
     */
    public static String getFileExtension(String fileName) {
        if (fileName == null) {
            throw new IllegalArgumentException("fileName must not be null!");
        }

        String extension = "";

        int index = fileName.lastIndexOf('.');
        if (index > 0) {
            extension = fileName.substring(index + 1);
        }

        return extension;

    }

} 

输出

Terminal

 Path: /path/foo.txt                  -> File Extension: txt
Path: .                              -> File Extension:
Path: ..                             -> File Extension:
Path: /path/run.exe                  -> File Extension: exe
Path: /path/makefile                 -> File Extension:
Path: /path/.htaccess                -> File Extension: htaccess
Path: /path/.tar.gz                  -> File Extension: gz
Path: /path/../makefile              -> File Extension: /makefile
Path: /path/dir.test/makefile        -> File Extension: test/makefile 

2。获取文件扩展名,严格版本。

这个例子实现了额外的检查,因为目录包含一个点,文件没有扩展名。

 Path: /path/../makefile              -> File Extension:
  Path: /path/dir.test/makefile        -> File Extension: 

额外的检查确保最后一个文件扩展名索引(位置)总是在最后一个文件分隔符(Windows 或 Unix)之后。

 if (indexOfLastExtension > indexOflastSeparator) {
      extension = fileName.substring(indexOfLastExtension + 1);
  } 

完整的例子。

GetFileExtension2.java

 package com.mkyong.io.howto;

import java.util.Map;

public class GetFileExtension2 {

    private static final String OUTPUT_FORMAT = "Path: %-30s -> File Extension: %s";
    private static final String WINDOWS_FILE_SEPARATOR = "\\";
    private static final String UNIX_FILE_SEPARATOR = "/";
    private static final String FILE_EXTENSION = ".";

    public static void main(String[] args) {

        String[] files = {
                "/path/foo.txt",
                ".",
                "..",
                "/path/run.exe",
                "/path/makefile",
                "/path/.htaccess",
                "/path/.tar.gz",
                "/path/../makefile",
                "/path/dir.test/makefile"
        };

        for (String file : files) {
            String output = String.format(OUTPUT_FORMAT, file, getFileExtensionImproved(file));
            System.out.println(output);
        }

    }

    /**
     * Add extra checking for below cases
     * <p>
     * "/path/../makefile",
     * "/path/dir.test/makefile"
     */
    public static String getFileExtensionImproved(String fileName) {

        if (fileName == null) {
            throw new IllegalArgumentException("fileName must not be null!");
        }

        String extension = "";

        int indexOfLastExtension = fileName.lastIndexOf(FILE_EXTENSION);

        // check last file separator, windows and unix
        int lastSeparatorPosWindows = fileName.lastIndexOf(WINDOWS_FILE_SEPARATOR);
        int lastSeparatorPosUnix = fileName.lastIndexOf(UNIX_FILE_SEPARATOR);

        // takes the greater of the two values, which mean last file separator
        int indexOflastSeparator = Math.max(lastSeparatorPosWindows, lastSeparatorPosUnix);

        // make sure the file extension appear after the last file separator
        if (indexOfLastExtension > indexOflastSeparator) {
            extension = fileName.substring(indexOfLastExtension + 1);
        }

        return extension;

    }

} 

输出

Terminal

 Path: /path/foo.txt                  -> File Extension: txt
Path: .                              -> File Extension:
Path: ..                             -> File Extension:
Path: /path/run.exe                  -> File Extension: exe
Path: /path/makefile                 -> File Extension:
Path: /path/.htaccess                -> File Extension: htaccess
Path: /path/.tar.gz                  -> File Extension: gz
Path: /path/../makefile              -> File Extension:
Path: /path/dir.test/makefile        -> File Extension: 

3。获取文件扩展名,硬编码版本

这个例子展示了如何硬编码一些文件扩展名并显示预定义的结果。例如,对于文件扩展名.tar.gz,我们希望显示tar.gz,而不是gz

GetFileExtension3.java

 package com.mkyong.io.howto;

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

public class GetFileExtension3 {

    private static final String OUTPUT_FORMAT = "Path: %-30s -> File Extension: %s";
    private static final String WINDOWS_FILE_SEPARATOR = "\\";
    private static final String UNIX_FILE_SEPARATOR = "/";
    private static final String FILE_EXTENSION = ".";
    private static final Map<String, String> KNOWN_EXTENSION = createKnownExtensionMap();

    public static void main(String[] args) {

        String[] files = {
                "/path/foo.txt",
                ".",
                "..",
                "/path/run.exe",
                "/path/makefile",
                "/path/.htaccess",
                "/path/.tar.gz",
                "/path/../makefile",
                "/path/dir.test/makefile"
        };

        for (String file : files) {
            String output = String.format(OUTPUT_FORMAT, file, getFileExtensionKnownExtension(file));
            System.out.println(output);
        }

    }

    public static String getFileExtensionImproved(String fileName) {

        if (fileName == null) {
            throw new IllegalArgumentException("fileName must not be null!");
        }

        String extension = "";

        int indexOfLastExtension = fileName.lastIndexOf(FILE_EXTENSION);

        int indexOflastSeparator = Math.max(
              fileName.lastIndexOf(WINDOWS_FILE_SEPARATOR),
              fileName.lastIndexOf(UNIX_FILE_SEPARATOR)
        );

        if (indexOfLastExtension > indexOflastSeparator) {
            extension = fileName.substring(indexOfLastExtension + 1);
        }

        return extension;

    }

    // hardcoded
    public static String getFileExtensionKnownExtension(final String fileName) {

        if (fileName == null) {
            throw new IllegalArgumentException("fileName must not be null!");
        }

        // if the file name is end with the hard coded extension.
        // Java 8 stream, loop map if key matches get value
        String extension = KNOWN_EXTENSION
                .entrySet()
                .stream()
                .filter(x -> fileName.endsWith(x.getKey()))
                .map(x -> x.getValue())
                .collect(Collectors.joining());

        if ("".equals(extension)) {
            extension = getFileExtensionImproved(fileName); // see example 2
        }

        return extension;

    }

    private static Map<String, String> createKnownExtensionMap() {
        Map<String, String> result = new HashMap<>();
        result.put(".tar.gz", "tar.gz");    // if .tar.gz, gets tar.gz
        result.put("makefile", "make");     // if makefile, get make
        //...extra
        return result;
    }

} 

输出

Terminal

 Path: /path/foo.txt                  -> File Extension: txt
Path: .                              -> File Extension:
Path: ..                             -> File Extension:
Path: /path/run.exe                  -> File Extension: exe
Path: /path/makefile                 -> File Extension: make
Path: /path/.htaccess                -> File Extension: htaccess
Path: /path/.tar.gz                  -> File Extension: tar.gz
Path: /path/../makefile              -> File Extension: make
Path: /path/dir.test/makefile        -> File Extension: make 

4。阿帕奇通用 IO

对于 Apache commons-io,我们可以使用FilenameUtils.getExtension(fileName)来获取一个文件的文件扩展名。

pom.xml

 <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.7</version>
  </dependency> 

完整的例子。

GetFileExtension4.java

 package com.mkyong.io.howto;

import org.apache.commons.io.FilenameUtils;

public class GetFileExtension4 {

    private static final String OUTPUT_FORMAT = "Path: %-30s -> File Extension: %s";

    public static void main(String[] args) {

        String[] files = {
                "/path/foo.txt",
                ".",
                "..",
                "/path/run.exe",
                "/path/makefile",
                "/path/.htaccess",
                "/path/.tar.gz",
                "/path/../makefile",
                "/path/dir.test/makefile"
        };

        for (String file : files) {
            String output = String.format(OUTPUT_FORMAT, file, FilenameUtils.getExtension(fileName));
            System.out.println(output);
        }

    }

} 

输出

Terminal

 Path: /path/foo.txt                  -> File Extension: txt
Path: .                              -> File Extension:
Path: ..                             -> File Extension:
Path: /path/run.exe                  -> File Extension: exe
Path: /path/makefile                 -> File Extension:
Path: /path/.htaccess                -> File Extension: htaccess
Path: /path/.tar.gz                  -> File Extension: gz
Path: /path/../makefile              -> File Extension:
Path: /path/dir.test/makefile        -> File Extension: 

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-io

参考文献

如何在 Java 中获取文件路径分隔符

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

对于文件路径或目录分隔符,Unix 系统引入了斜杠字符/作为目录分隔符,微软 Windows 引入了反斜杠字符\作为目录分隔符。简单来说,这就是 UNIX 上的/和 Windows 上的\

在 Java 中,我们可以使用以下三种方法来获得与平台无关的文件路径分隔符。

  1. System.getProperty("file.separator")
  2. FileSystems.getDefault().getSeparator()
  3. File.separator Java IO

1.系统属性

通过系统属性T0 获取文件路径分隔符。

GetFileSeparator1.java

 package com.mkyong.io.howto;

public class GetFileSeparator {

    public static void main(String[] args) {

        // unix / , windows \
        String separator = System.getProperty("file.separator");
        System.out.println(separator);

    }

} 

2.Java 九

Java 7,九FileSystems.getDefault().getSeparator()中的一个。

GetFileSeparator2.java

 package com.mkyong.io.howto;

import java.nio.file.FileSystems;

public class GetFileSeparator2 {

    public static void main(String[] args) {

        // unix / , windows \
        String separator = FileSystems.getDefault().getSeparator();
        System.out.println(separator);

    }

} 

3.Java IO

Java IO File.separator例子。

GetFileSeparator3.java

 package com.mkyong.io.howto;

import java.io.File;

public class GetFileSeparator3 {

    public static void main(String[] args) {

        // unix / , windows \
        String separator = File.separator;
        System.out.println(separator);

    }

} 

4.哪一个?

对于System.getProperty("file.separator"),我们可以通过System.setProperty()或命令行-Dfile.separator覆盖该值。File.separatorFileSystems.getDefault().getSeparator()将返回相同的分离器。

读了这个遗留文件 I/O 代码的弊端,挑选了 Java NIO FileSystems.getDefault().getSeparator()

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-io

参考

如何在 Java 中获取文件大小

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

在 Java 中,我们可以使用 Files.size(path) 来获取文件的大小,以字节为单位。

 // size in bytes
  long bytes = Files.size(path); 

1.文件大小(NIO)

这个例子使用 NIO Files.size(path)来打印图像文件的大小(140 kb)。

GetFileSize.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 GetFileSize {

    public static void main(String[] args) {

        // this image is around 140kb
        String fileName = "/home/mkyong/Pictures/temp.png";
        printFileSizeNIO(fileName);

    }

    public static void printFileSizeNIO(String fileName) {

        Path path = Paths.get(fileName);

        try {

            // size of a file (in bytes)
            long bytes = Files.size(path);
            System.out.println(String.format("%,d bytes", bytes));
            System.out.println(String.format("%,d kilobytes", bytes / 1024));

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

} 

输出

 143,041 bytes
139 kilobytes 

2.File.length(传统 IO)

在过去(Java 7 之前),我们可以使用遗留 IO File.length()来获取文件的字节大小。这个例子将字节格式化到 yottabytes ,只是为了好玩。

GetFileSize2

 package com.mkyong.io.howto;

import java.io.File;

public class GetFileSize2 {

    public static void main(String[] args) {

        String fileName = "/home/mkyong/Pictures/temp.png";
        printFileSize(fileName);
    }

    public static void printFileSize(String fileName) {

        File file = new File(fileName);

        if (file.exists()) {

            // size of a file (in bytes)
            long bytes = file.length();

            long kilobytes = (bytes / 1024);
            long megabytes = (kilobytes / 1024);
            long gigabytes = (megabytes / 1024);
            long terabytes = (gigabytes / 1024);
            long petabytes = (terabytes / 1024);
            long exabytes = (petabytes / 1024);
            long zettabytes = (exabytes / 1024);
            long yottabytes = (zettabytes / 1024);

            System.out.println(String.format("%,d bytes", bytes));
            System.out.println(String.format("%,d kilobytes", kilobytes));
            System.out.println(String.format("%,d megabytes", megabytes));
            System.out.println(String.format("%,d gigabytes", gigabytes));
            System.out.println(String.format("%,d terabytes", terabytes));
            System.out.println(String.format("%,d petabytes", petabytes));
            System.out.println(String.format("%,d exabytes", exabytes));
            System.out.println(String.format("%,d zettabytes", zettabytes));
            System.out.println(String.format("%,d yottabytes", yottabytes));

        } else {
            System.out.println("File does not exist!");
        }

    }

} 

输出

Terminal

 143,041 bytes
139 kilobytes
0 megabytes
0 gigabytes
0 terabytes
0 petabytes
0 exabytes
0 zettabytes
0 yottabytes 

截至发稿时,磁盘存储仍以 TB 为单位,是 Pb 级硬盘还是 SSD 存在?

参考

如何在 Java 中获得一个目录的大小

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-get-size-of-a-directory-in-java/

在 Java 中,我们可以用Files.size来获取一个文件的大小;对于目录或文件夹的大小,我们需要递归地计算一个目录的大小(所有文件的Files.size之和)。

这个例子展示了几种获取目录或文件夹大小的常用方法。

  1. FileVisitor (Java 7)
  2. Files.walk (Java 8)
  3. FileUtils.sizeOfDirectory(阿帕奇通用 IO)
  4. 所有文件的总和file.length。(传统 IO)

1.目录大小–file visitor(Java 7)

这个例子使用了FileVisitor来访问指定路径中的所有文件,并对所有文件的大小求和。

 // size of directory in bytes
  public static long getDirectorySizeJava7(Path path) {

      AtomicLong size = new AtomicLong(0);

      try {

          Files.walkFileTree(path, new SimpleFileVisitor<>() {

              @Override
              public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                  // sum size of all visit file
                  size.addAndGet(attrs.size());
                  return FileVisitResult.CONTINUE;
              }

              @Override
              public FileVisitResult visitFileFailed(Path file, IOException e) {
                  System.out.printf("Failed to get size of %s%n%s", file, e);
                  return FileVisitResult.CONTINUE;
              }

          });
      } catch (IOException e) {
          System.out.printf("%s", e);
      }

      return size.get();

  } 

2.目录大小–files . walk(Java 8)

这个例子使用 Java 8 Files.walkStream递归地遍历一个目录,并对所有文件的大小求和。

 // size of directory in bytes
  public static long getDirectorySizeJava8(Path path) {

      long size = 0;

      // need close Files.walk
      try (Stream<Path> walk = Files.walk(path)) {

          size = walk
                  //.peek(System.out::println) // debug
                  .filter(Files::isRegularFile)
                  .mapToLong(p -> {
                      // ugly, can pretty it with an extract method
                      try {
                          return Files.size(p);
                      } catch (IOException e) {
                          System.out.printf("Failed to get size of %s%n%s", p, e);
                          return 0L;
                      }
                  })
                  .sum();

      } catch (IOException e) {
          System.out.printf("IO errors %s", e);
      }

      return size;

  } 

3.目录大小–FileUtils(Apache 公共 IO)

这个例子使用 Apache Common IO FileUtils.sizeOfDirectory来获取目录的大小。

pom.xml

 <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.7</version>
  </dependency> 
 public static long getDirectorySizeCommonIO(File dir) {

      return FileUtils.sizeOfDirectory(dir);

  } 

4.传统 IO

在遗留 IO 中,我们可以使用file.listFiles()递归地遍历一个目录,使用file.length()对所有文件的大小求和。

 public static long getDirectorySizeLegacy(File dir) {

      long length = 0;
      File[] files = dir.listFiles();
      if (files != null) {
          for (File file : files) {
              if (file.isFile())
                  length += file.length();
              else
                  length += getDirectorySizeLegacy(file);
          }
      }
      return length;

  } 

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-io

参考

如何用 jQuery 获取文本框值

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jquery/how-to-get-textbox-value-with-jquery/

要获得文本框的值,可以使用 jQuery val() 函数。

举个例子,

  1. $('input:textbox ')。val()–获取文本框值。
  2. $('input:textbox ')。val("新文本消息")–设置文本框值。

文本框示例

 <html>
<head>
<title>jQuery get textbox value example</title>

<script type="text/javascript" src="jquery-1.3.2.min.js"></script>

</head>

<body>

<h1>jQuery get textbox value example</h1>

<h2>TextBox value : <label id="msg"></label></h2>

<div style="padding:16px;">
	TextBox : <input type="textbox" value="Type something"></input>
</div>

<button id="Get">Get TextBox Value</button> 
<button id="Set">Set To "ABC"</button> 
<button id="Reset">Reset It</button>

<script type="text/javascript">
    $("button:#Get").click(function () {

	$('#msg').html($('input:textbox').val());

    });

    $("button:#Reset").click(function () {

	$('#msg').html("");
	$('input:textbox').val("");

    });

    $("button:#Set").click(function () {

	$('input:textbox').val("ABC");
	$('#msg').html($('input:textbox').val());

    });

</script>

</body>
</html> 

http://web.archive.org/web/20220618072948if_/https://www.mkyong.com/wp-content/uploads/jQuery/jQuery-get-textbox-value.html

Try Demo

如何在 Java 中获取当前工作目录

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-get-the-current-working-directory-in-java/

在 Java 中,我们可以使用System.getProperty("user.dir")来获取当前的工作目录,即程序启动的目录。

 String dir = System.getProperty("user.dir");

  // directory from where the program was launched
  // e.g /home/mkyong/projects/core-java/java-io
  System.out.println(dir); 

这个系统属性user.dir的一个好处是,我们可以通过一个-D参数轻松覆盖系统属性,例如:

 java -Duser.dir=/home/mkyong/ -jar abc.jar 

1.工作目录

下面的程序显示了获取当前工作目录的不同方式,如FilePathsFileSystems或系统属性;所有方法都将返回相同的结果。

CurrentWorkingDirectory.java

 package com.mkyong.io.howto;

import java.io.File;
import java.nio.file.FileSystems;
import java.nio.file.Paths;

public class CurrentWorkingDirectory {

    public static void main(String[] args) {

        printCurrentWorkingDirectory1();
        printCurrentWorkingDirectory2();
        printCurrentWorkingDirectory3();
        printCurrentWorkingDirectory4();

    }

    // System Property
    private static void printCurrentWorkingDirectory1() {
        String userDirectory = System.getProperty("user.dir");
        System.out.println(userDirectory);
    }

    // Path, Java 7
    private static void printCurrentWorkingDirectory2() {
        String userDirectory = Paths.get("")
                .toAbsolutePath()
                .toString();
        System.out.println(userDirectory);
    }

    // File("")
    private static void printCurrentWorkingDirectory3() {
        String userDirectory = new File("").getAbsolutePath();
        System.out.println(userDirectory);
    }

    // FileSystems
    private static void printCurrentWorkingDirectory4() {
        String userDirectory = FileSystems.getDefault()
                .getPath("")
                .toAbsolutePath()
                .toString();
        System.out.println(userDirectory);
    }

} 

输出

Terminal

 /home/mkyong/projects/core-java/java-io
/home/mkyong/projects/core-java/java-io
/home/mkyong/projects/core-java/java-io
/home/mkyong/projects/core-java/java-io 

通常,我们使用System.getProperty("user.dir")来获取当前工作目录。

2.JAR 文件的工作目录?

不要使用System.getProperty("user.dir")FilePath来访问JAR文件中的文件,这不会起作用。相反,我们应该使用getClassLoader().getResourceAsStream()

 // get a file from the resources folder, root of classpath in JAR
private InputStream getFileFromResourceAsStream(String fileName) {

    // The class loader that loaded the class
    ClassLoader classLoader = getClass().getClassLoader();
    InputStream inputStream = classLoader.getResourceAsStream(fileName);

    // the stream holding the file content
    if (inputStream == null) {
        throw new IllegalArgumentException("file not found! " + fileName);
    } else {
        return inputStream;
    }

} 


以上代码摘自本资源文件夹中读取的一个文件。请参考示例 2 来访问 JAR 文件中的文件。

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-io

参考

如何在 Java 中获取文件创建日期

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-get-the-file-creation-date-in-java/

在 Java 中(@ 1.7 以后),我们可以使用 NIO Files.readAttributes来获取所有的文件元数据,包括文件创建日期。

 Path file = Paths.get(fileName);

  BasicFileAttributes attr = Files.readAttributes(file, BasicFileAttributes.class);

  System.out.println("creationTime: " + attr.creationTime());
  // creationTime: 2020-07-20T09:29:54.627222Z 

1.Files.readAttributes (NIO)

这个例子使用Files.readAttributes来打印文件创建日期。

GetCreationDate1.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.attribute.BasicFileAttributes;

public class GetCreationDate1 {

    public static void main(String[] args) {

        String fileName = "/home/mkyong/test.txt";

        try {

            Path file = Paths.get(fileName);

            BasicFileAttributes attr =
                Files.readAttributes(file, BasicFileAttributes.class);

            System.out.println("creationTime: " + attr.creationTime());

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

} 

输出

 creationTime: 2020-07-20T09:29:54.627222Z 

我们也可以使用相同的代码来获得一个目录的创建日期。

进一步阅读
阅读此示例以将 FileTime 转换为另一种日期时间格式

2.Files.getAttribute (NIO)

Files.readAttributes将返回所有文件元数据,如创建时间、最后修改时间、文件大小等。

我们可以使用Files.getAttribute来返回一个指定的文件元数据,例如,creationTime属性。

GetCreationDate2.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.attribute.FileTime;

public class GetCreationDate2 {

    public static void main(String[] args) {

        String fileName = "/home/mkyong/test";

        try {

            Path file = Paths.get(fileName);

            FileTime creationTime =
                (FileTime) Files.getAttribute(file, "creationTime");

            System.out.println("creationTime: " + creationTime);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

} 

3.Java 7 之前

这个示例使用Runtime.getRuntime().exec发出一个dir file /tc系统命令来列出 Windows 上的文件创建日期,并手动解析内容以提取文件创建日期。

P.S 在 Java 7 之前,没有官方的 API 来获取文件创建日期。

3.1 查看 Windows 上的dir /tc命令。

Terminal

 C:\> dir c:\logfile.log /tc
 Volume in drive C has no label.
 Volume Serial Number is 0410-1EC3

 Directory of c:\

31/05/2010  08:05                14 logfile.log
               1 File(s)             14 bytes
               0 Dir(s)  35,389,460,480 bytes free

C:\> dir /?

Displays a list of files and subdirectories in a directory.

 //...
 /T          Controls which time field displayed or used for sorting
 timefield   C  Creation
             A  Last Access
             W  Last Written 

3.2 Java 示例。

GetFileCreation3.java

 package com.mkyong.io.howto;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class GetFileCreation3 {

    public static void main(String[] args) {

        Process proc;
        BufferedReader br = null;

        try {

            proc = Runtime.getRuntime()
                  .exec("cmd /c dir c:\\logfile.log /tc");

            br = new BufferedReader(
                  new InputStreamReader(proc.getInputStream()));

            String data = "";
            //it's quite stupid but work, ignore first 5 lines
            for (int i = 0; i < 6; i++) {
                data = br.readLine();
            }

            System.out.println("Extracted value : " + data);

            //split by space
            StringTokenizer st = new StringTokenizer(data);
            String date = st.nextToken(); //Get date
            String time = st.nextToken(); //Get time

            System.out.println("Creation Date  : " + date);
            System.out.println("Creation Time  : " + time);

        } catch (IOException e) {

            e.printStackTrace();

        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
} 

输出

Terminal

 Extracted value : 31/05/2010  08:05  14 logfile.log
Creation Date  : 31/05/2010
Creation Time  : 08:05 

上面的代码仍然可以工作,但是要获得一个文件创建时间太复杂了,除非你无法升级 JVM 否则,请使用 Java 7+ NIO Files.readAttributes

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-io

参考

如何在 Java 中获取文件的最后修改日期

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-get-the-file-last-modified-date-in-java/

在 Java 中,我们可以使用Files.readAttributes()来获取文件元数据或属性,然后使用lastModifiedTime()来显示文件的最后修改日期。

 Path file = Paths.get("/home/mkyong/file.txt");

  BasicFileAttributes attr = Files.readAttributes(file, BasicFileAttributes.class);

  System.out.println("lastModifiedTime: " + attr.lastModifiedTime()); 

1.基本文件属性(NIO)

这个例子使用java.nio.*来显示文件属性或元数据——创建时间、最后访问时间和最后修改时间。

GetLastModifiedTime1.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.attribute.BasicFileAttributes;

public class GetLastModifiedTime1 {

    public static void main(String[] args) {

        String fileName = "/home/mkyong/file.txt";

        try {

            Path file = Paths.get(fileName);
            BasicFileAttributes attr =
                Files.readAttributes(file, BasicFileAttributes.class);

            System.out.println("creationTime: " + attr.creationTime());
            System.out.println("lastAccessTime: " + attr.lastAccessTime());
            System.out.println("lastModifiedTime: " + attr.lastModifiedTime());

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

} 

输出

Terminal

 creationTime: 2020-07-20T09:29:54.627222Z
lastAccessTime: 2020-07-21T12:15:56.699971Z
lastModifiedTime: 2020-07-20T09:29:54.627222Z 

BasicFileAttributes也适用于目录,我们可以使用相同的代码来显示目录的最后修改时间。

进一步阅读
阅读此示例以将 FileTime 转换为另一种日期时间格式

2.File.lastModified(旧 IO)

对于遗留 IO,我们可以使用File.lastModified()来获取最后修改的时间;该方法返回自[纪元时间]以来以毫秒为单位测量的长值(https://en . Wikipedia . org/wiki/Epoch _(计算))。我们可以使用SimpleDateFormat使它成为一种更易于阅读的格式。

GetLastModifiedTime2.java

 package com.mkyong.io.howto;

import java.io.File;
import java.text.SimpleDateFormat;

public class GetLastModifiedTime2 {

    public static void main(String[] args) {

        String fileName = "/home/mkyong/test";

        File file = new File(fileName);

        System.out.println("Before Format : " + file.lastModified());

        SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");

        System.out.println("After Format : " + sdf.format(file.lastModified()));

    }

} 

输出

Terminal

 Before Format : 1595237394627
After Format : 07/20/2020 17:29:54 

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-io

参考

如何在 Java 中获取文件的文件路径

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-get-the-filepath-of-a-file-in-java/

在 Java 中,对于 NIO 路径,我们可以使用path.toAbsolutePath()来获取文件路径;对于遗留 IO 文件,我们可以使用file.getAbsolutePath()来获取文件路径。

对于包含...的符号链接或文件路径,我们可以使用path.toRealPath()file.getCanonicalPath()来获取真正的文件路径。

下面是FilePath的映射。

  1. file.getAbsolutePath() < = > path.toAbsolutePath()
  2. file.getCanonicalPath() < = > path.toRealPath()
  3. file.getParent() < = > path.getParent()

1.获取文件的文件路径(NIO 路径)。

对于java.nio.file.Path,我们可以使用下面的 API 来获取一个文件的文件路径。

  1. path.toAbsolutePath()–完整的文件路径。
  2. path.toRealPath())–对于符号链接或解析路径名中的...符号,默认为跟随链接。
  3. path.getParent()–获取路径的父目录。

1.1 路径= /home/mkyong/test/file.txt

 Path path = Paths.get("/home/mkyong/test/file.txt");

path                      : /home/mkyong/test/file.txt
path.toAbsolutePath()     : /home/mkyong/test/file.txt
path.getParent()          : /home/mkyong/test
path.toRealPath()         : /home/mkyong/test/file.txt 

1.2 Path = file.txt,文件参照当前工作目录 + file.txt

 Path path = Paths.get("file.txt");

path                      : file.txt
path.toAbsolutePath()     : /home/mkyong/projects/core-java/java-io/file.txt
path.getParent()          : null
path.toRealPath()         : /home/mkyong/projects/core-java/java-io/file.txt 

1.3 Path = /home/mkyong/test/soft-link,符号链接。

 $ ln -s
  /home/mkyong/projects/core-java/java-io/src/main/java/com/mkyong/io/howto/GetFilePath.java
  /home/mkyong/test/soft-link 
 Path path = Paths.get("/home/mkyong/test/soft-link");

path                      : /home/mkyong/test/soft-link
path.toAbsolutePath()     : /home/mkyong/test/soft-link
path.getParent()          : /home/mkyong/test
path.toRealPath()         : /home/mkyong/projects/core-java/java-io/src/main/java/com/mkyong/io/howto/GetFilePath.java 

1.4 路径= /home/mkyong/test/../hello.txt

 Path path = Paths.get("/home/mkyong/test/../hello.txt");

path                      : /home/mkyong/test/../hello.txt
path.toAbsolutePath()     : /home/mkyong/test/../hello.txt
path.getParent()          : /home/mkyong/test/..
path.toRealPath()         : /home/mkyong/hello.txt 

下面 1.5 是一个完整的 Java 例子,用来获取不同Path的文件路径。

GetFilePath1.java

 package com.mkyong.io.howto;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;

public class GetFilePath1 {

    public static void main(String[] args) {

        // full path
        Path path1 = Paths.get("/home/mkyong/test/file.txt");
        System.out.println("\n[Path] : " + path1);
        printPath(path1);

        // file name
        Path path2 = Paths.get("file.txt");
        System.out.println("\n[Path] : " + path2);
        printPath(path2);

        // soft or symbolic link
        Path path3 = Paths.get("/home/mkyong/test/soft-link");
        System.out.println("\n[Path] : " + path3);
        printPath(path3);

        // a path contains `..`
        Path path4 = Paths.get("/home/mkyong/test/../hello.txt");
        System.out.println("\n[Path] : " + path4);
        printPath(path4);

    }

    static void printPath(Path path) {

        System.out.printf("%-25s : %s%n", "path", path);
        System.out.printf("%-25s : %s%n", "path.toAbsolutePath()",
                                                path.toAbsolutePath());
        System.out.printf("%-25s : %s%n", "path.getParent()", path.getParent());
        System.out.printf("%-25s : %s%n", "path.getRoot()", path.getRoot());

        try {

            if (Files.notExists(path)) {
                return;
            }

            // default, follow symbolic link
            System.out.printf("%-25s : %s%n", "path.toRealPath()",
                                                  path.toRealPath());
            // no follow symbolic link
            System.out.printf("%-25s : %s%n", "path.toRealPath(nofollow)",
                path.toRealPath(LinkOption.NOFOLLOW_LINKS));

            // alternative to check isSymbolicLink
            /*if (Files.isSymbolicLink(path)) {
                Path link = Files.readSymbolicLink(path);
                System.out.println(link);
            }*/

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

} 

输出

Terminal

 [Path] : /home/mkyong/test/file.txt
path                      : /home/mkyong/test/file.txt
path.toAbsolutePath()     : /home/mkyong/test/file.txt
path.getParent()          : /home/mkyong/test
path.getRoot()            : /
path.toRealPath()         : /home/mkyong/test/file.txt
path.toRealPath(nofollow) : /home/mkyong/test/file.txt

[Path] : file.txt
path                      : file.txt
path.toAbsolutePath()     : /home/mkyong/projects/core-java/java-io/file.txt
path.getParent()          : null
path.getRoot()            : null
path.toRealPath()         : /home/mkyong/projects/core-java/java-io/file.txt
path.toRealPath(nofollow) : /home/mkyong/projects/core-java/java-io/file.txt

[Path] : /home/mkyong/test/soft-link
path                      : /home/mkyong/test/soft-link
path.toAbsolutePath()     : /home/mkyong/test/soft-link
path.getParent()          : /home/mkyong/test
path.getRoot()            : /
path.toRealPath()         : /home/mkyong/projects/core-java/java-io/src/main/java/com/mkyong/io/howto/GetFilePath.java
path.toRealPath(nofollow) : /home/mkyong/test/soft-link

[Path] : /home/mkyong/test/../hello.txt
path                      : /home/mkyong/test/../hello.txt
path.toAbsolutePath()     : /home/mkyong/test/../hello.txt
path.getParent()          : /home/mkyong/test/..
path.getRoot()            : /
path.toRealPath()         : /home/mkyong/hello.txt
path.toRealPath(nofollow) : /home/mkyong/hello.txt 

2.获取文件的文件路径(旧文件)

对于遗留 IO java.io.File,我们可以使用下面的 API 来获取文件的文件路径。

  1. file.getAbsolutePath() = path.toAbsolutePath()
  2. file.getCanonicalPath() = path.toRealPath()
  3. file.getParent() = path.getParent()

GetFilePath2.java

 package com.mkyong.io.howto;

import java.io.File;
import java.io.IOException;

public class GetFilePath2 {

    public static void main(String[] args) {

        // full file path
        File file1 = new File("/home/mkyong/test/file.txt");
        System.out.println("[File] : " + file1);
        printFilePath(file1);

        // a file name
        File file2 = new File("file.txt");
        System.out.println("\n[File] : " + file2);
        printFilePath(file2);

        // a soft or symbolic link
        File file3 = new File("/home/mkyong/test/soft-link");
        System.out.println("\n[File] : " + file3);
        printFilePath(file3);

        // a file contain `..`
        File file4 = new File("/home/mkyong/test/../hello.txt");
        System.out.println("\n[File] : " + file4);
        printFilePath(file4);

    }

    // If a single file name, not full path, the file refer to
    // System.getProperty("user.dir") + file
    static void printFilePath(File file) {
        // print File = print file.getPath()
        System.out.printf("%-25s : %s%n", "file.getPath()", file.getPath());
        System.out.printf("%-25s : %s%n", "file.getAbsolutePath()",
                                              file.getAbsolutePath());
        try {
            System.out.printf("%-25s : %s%n", "file.getCanonicalPath()",
                                                file.getCanonicalPath());
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.printf("%-25s : %s%n", "Parent Path", getParentPath(file));
    }

    // if unable to get parent, try substring to get the parent folder.
    private static String getParentPath(File file) {
        if (file.getParent() == null) {
            String absolutePath = file.getAbsolutePath();
            return absolutePath.substring(0,
                          absolutePath.lastIndexOf(File.separator));
        } else {
            return file.getParent();
        }
    }

} 

输出

Terminal

 [File] : /home/mkyong/test/file.txt
file.getPath()            : /home/mkyong/test/file.txt
file.getAbsolutePath()    : /home/mkyong/test/file.txt
file.getCanonicalPath()   : /home/mkyong/test/file.txt
Parent Path               : /home/mkyong/test

[File] : file.txt
file.getPath()            : file.txt
file.getAbsolutePath()    : /home/mkyong/projects/core-java/java-io/file.txt
file.getCanonicalPath()   : /home/mkyong/projects/core-java/java-io/file.txt
Parent Path               : /home/mkyong/projects/core-java/java-io

[File] : /home/mkyong/test/soft-link
file.getPath()            : /home/mkyong/test/soft-link
file.getAbsolutePath()    : /home/mkyong/test/soft-link
file.getCanonicalPath()   : /home/mkyong/projects/core-java/java-io/src/main/java/com/mkyong/io/howto/GetFilePath.java
Parent Path               : /home/mkyong/test

[File] : /home/mkyong/test/../hello.txt
file.getPath()            : /home/mkyong/test/../hello.txt
file.getAbsolutePath()    : /home/mkyong/test/../hello.txt
file.getCanonicalPath()   : /home/mkyong/hello.txt
Parent Path               : /home/mkyong/test/.. 

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-io

参考

如何在 Struts 2 中获得 HttpServletRequest

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/struts2/how-to-get-the-httpservletrequest-in-struts-2/

在 Struts 2 中,可以使用以下两种方法来获取 HttpServletRequest 对象。

1.ServletActionContext

直接从org . Apache . struts 2 . servletactioncontext获取 HttpServletRequest 对象。

 import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;

public class LocaleAction{
	//business logic
	public String execute() {
		HttpServletRequest request = ServletActionContext.getRequest();
		return "SUCCESS";
	}
} 

2.ServletRequestAware

使您的类实现了org . Apache . struts 2 . interceptor . servletrequestaware

When Struts 2 ‘servlet-config‘ interceptor is seeing that an Action class is implemented the ServletRequestAware interface, it will pass a HttpServletRequest reference to the requested Action class via the setServletRequest() method.

 import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.interceptor.ServletRequestAware;

public class LocaleAction implements ServletRequestAware{

	HttpServletRequest request;

	//business logic
	public String execute() {
		String param = getServletRequest().getParameter("param");
		return "SUCCESS";

	}

	public void setServletRequest(HttpServletRequest request) {
		this.request = request;
	}

	public HttpServletRequest getServletRequest() {
		return this.request;
	}
} 

Struts 2 documentation is recommended ServletRequestAware instead of ServletActionContext. ## 参考

  1. http://struts . Apache . org/2 . x/docs/how-can-we-access-the-http servlet request . html
  2. http://struts . Apache . org/2 . 0 . 6/struts 2-core/API docs/org/Apache/struts 2/interceptor/servletrequestaware . html

httpservletrequest struts2

如何在 Struts 2 中获得 HttpServletResponse

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/struts2/how-to-get-the-httpservletresponse-in-struts-2/

在 Struts 2 中,您可以使用以下两种方法来获取HttpServletResponse对象。

1.ServletActionContext

通过ServletActionContext类访问HttpServletResponse

 package com.mkyong.common.action;

import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;

public class LocaleAction{
	//business logic
	public String execute() {
		HttpServletResponse response = ServletActionContext.getResponse();

		return "SUCCESS";
	}
} 

2.ServletResponseAware

通过实现ServletResponseAware接口来访问HttpServletResponse,并覆盖 setServletResponse()方法。

Note
When Struts 2 ‘servlet-config‘ interceptor is seeing that an Action class is implemented the ServletResponseAware interface, it will pass a HttpServletResponse reference to the requested Action class via the setServletResponse() menthod.

当然,您可以创建一个自定义的getServletResponse()来轻松获得HttpServletResponse

 package com.mkyong.common.action;

import java.util.Locale;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.interceptor.ServletResponseAware;

public class LocaleAction implements ServletResponseAware{

	HttpServletResponse response;

	//business logic
	public String execute() {
		Locale locale = getServletResponse().getLocale();
		return "SUCCESS";
	}

	public void setServletResponse(HttpServletResponse response) {
		this.response = response;
	}
	public HttpServletResponse getServletResponse() {
		return this.response;
	}	
} 

两种机制都获得相同的HttpServletResponse对象,但是 Struts 2 文档推荐使用ServletResponseAware,参见下面的参考资料:

参考

  1. http://struts . Apache . org/2 . x/docs/how-can-we-access-the-http servlet response . html
  2. http://struts . Apache . org/2 . 1 . 2/struts 2-core/API docs/org/Apache/struts 2/interceptor/servletresponseaware . html

httpservletresponse struts2

如何在 Struts 2 中获得 ServletContext

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/struts2/how-to-get-the-servletcontext-in-struts-2/

在 Struts 2 中,可以使用以下两种方法来获取 ServletContext 对象。

1.ServletActionContext

直接从org . Apache . struts 2 . servletactioncontext获取 ServletContext 对象。

 import javax.servlet.ServletContext;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;

public class CustomerAction extends ActionSupport{

	public String execute() throws Exception {

		ServletContext context = ServletActionContext.getServletContext();

		return SUCCESS;

	}

} 

2.ServletContextAware

使您的类实现org . Apache . struts 2 . util . servletcontextaware接口。

When Struts 2 ‘servlet-config’ interceptor is seeing that an Action class is implemented the ServletContextAware interface, it will pass a ServletContext reference to the requested Action class via the setServletContext() method.

 import javax.servlet.ServletContext;
import org.apache.struts2.util.ServletContextAware;
import com.opensymphony.xwork2.ActionSupport;

public class CustomerAction 
    extends ActionSupport implements ServletContextAware{

	ServletContext context;

	public String execute() throws Exception {

		return SUCCESS;

	}

	public void setServletContext(ServletContext context) {
		this.context = context;
	}
} 

参考

  1. Struts 2 ServletContextAware 文档

如何在 Java 中获取临时文件路径

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-get-the-temporary-file-path-in-java/

在 Java 中,我们可以使用System.getProperty("java.io.tmpdir")来获取默认的临时文件位置。

  1. 对于 Windows,默认的临时文件夹是%USER%\AppData\Local\Temp
  2. 对于 Linux,默认的临时文件夹是/tmp

1.java.io.tmpdir

在 Ubuntu Linux 上运行下面的 Java 程序。

TempFilePath1

 package com.mkyong.io.temp;

public class TempFilePath1 {

    public static void main(String[] args) {

        String tmpdir = System.getProperty("java.io.tmpdir");
        System.out.println("Temp file path: " + tmpdir);

    }

} 

输出

 Temp file path: /tmp 

2.创建临时文件

或者,我们可以创建一个临时文件并通过substring文件路径来获得临时文件的位置。

2.1 Java NIO 示例。

TempFilePath2.java

 package com.mkyong.io.temp;

import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;

public class TempFilePath2 {

    public static void main(String[] args) {

        // Java NIO
        try {
            Path temp = Files.createTempFile("", ".tmp");

            String absolutePath = temp.toString();
            System.out.println("Temp file : " + absolutePath);

            String separator = FileSystems.getDefault().getSeparator();
            String tempFilePath = absolutePath
                  .substring(0, absolutePath.lastIndexOf(separator));

            System.out.println("Temp file path : " + tempFilePath);

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

} 

输出

 Temp file : /tmp/log_11536339146653799756.tmp
Temp file path : /tmp 

2.2 Java IO 示例。

TempFilePath3.java

 package com.mkyong.io.temp;

import java.io.File;
import java.io.IOException;

public class TempFilePath3 {

    public static void main(String[] args) {

        // Java IO
        try {
            File temp = File.createTempFile("log_", ".tmp");
            System.out.println("Temp file : " + temp.getAbsolutePath());

            String absolutePath = temp.getAbsolutePath();
            String tempFilePath = absolutePath
                  .substring(0, absolutePath.lastIndexOf(File.separator));

            System.out.println("Temp file path : " + tempFilePath);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

} 

输出

 Temp file : /tmp/log_9219838414378386507.tmp
Temp file path : /tmp 

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-io

参考

Java–计算文件中的行数

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-get-the-total-number-of-lines-of-a-file-in-java/

本文展示了几个 Java 示例来获取文件中的总行数。步骤是相似的:

  1. 打开文件。
  2. 逐行读取,每行增加计数+ 1。
  3. 关闭文件。
  4. 读伯爵。

测试 Java 方法:

  1. Files.lines
  2. BufferedReader
  3. LineNumberReader
  4. BufferedInputStream

在本文的最后,我们还展示了在一个包含 500 万行、每行 1053 个字符的大文件中计算总行数的不同方法的性能。

1.Files.lines (Java 8)

这个Files.lines是最简单的实现。

 public static long countLineJava8(String fileName) {

      Path path = Paths.get(fileName);

      long lines = 0;
      try {

          // much slower, this task better with sequence access
          //lines = Files.lines(path).parallel().count();

          lines = Files.lines(path).count();

      } catch (IOException e) {
          e.printStackTrace();
      }

      return lines;

  } 

2.缓冲阅读器

本例使用BufferedReader逐行读取,并增加计数。

 public static long countLineBufferedReader(String fileName) {

      long lines = 0;
      try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
          while (reader.readLine() != null) lines++;
      } catch (IOException e) {
          e.printStackTrace();
      }
      return lines;

  } 

3.行号阅读器

这个LineNumberReader和上面的BufferedReader类似。

 public static long countLineNumberReader(String fileName) {

      File file = new File(fileName);

      long lines = 0;

      try (LineNumberReader lnr = new LineNumberReader(new FileReader(file))) {

          while (lnr.readLine() != null) ;

          lines = lnr.getLineNumber();

      } catch (IOException e) {
          e.printStackTrace();
      }

      return lines;

  } 

4.缓冲输入流

这个BufferedInputStream例子是从这个 StackOverflow 答案里抄来的。

 public static long countLineFast(String fileName) {

      long lines = 0;

      try (InputStream is = new BufferedInputStream(new FileInputStream(fileName))) {
          byte[] c = new byte[1024];
          int count = 0;
          int readChars = 0;
          boolean endsWithoutNewLine = false;
          while ((readChars = is.read(c)) != -1) {
              for (int i = 0; i < readChars; ++i) {
                  if (c[i] == '\n')
                      ++count;
              }
              endsWithoutNewLine = (c[readChars - 1] != '\n');
          }
          if (endsWithoutNewLine) {
              ++count;
          }
          lines = count;
      } catch (IOException e) {
          e.printStackTrace();
      }

      return lines;
  } 

5.基准

5.1 创建一个包含 500 万行、每行 1053 个字符、文件大小为 5G 的大文件。

 public static void writeLargeFile() {

      String fileName = "/home/mkyong/large-file.txt";

      // 1053 chars per line
      String content = "Hello 123456 ";
      content = content + content + content;
      content = content + content + content;
      content = content + content + content;
      content = content + content + content;

      System.out.println(content.length()); // 1053

      try (BufferedWriter bw = new BufferedWriter(new FileWriter(fileName))) {

          for (int i = 0; i < 5_000_000; i++) {
              bw.write(content);
              bw.write(System.lineSeparator());
          }

      } catch (IOException e) {
          e.printStackTrace();
      }

  } 

5.2 同样的方法重新运行 5-10 次,得到平均基准,结果如下:

  1. Files.lines–6-8 秒。
  2. BufferedReader–6-8 秒。
  3. LineNumberReader–6-8 秒。
  4. BufferedInputStream–4-5 秒。

这个BufferedInputStream ( StackOverflow 回答),是计算一个大文件(5G 文件大小,500 万行)行数的最快方法。尽管如此,差别并不明显,而且实现容易出错,有点复杂。如果我们测试一个更小的文件,比如 1G 的文件大小和 100 万行,我们几乎注意不到区别。

最后,Java NIO Files.lines易于使用,性能也没有太大的不同,是计算文件行数的最佳选择。

6.wc -l

在 Linux 上,命令wc -l是计算文件行数的最快方法。

Terminal

 $ time wc -l large-file.txt
5000000 large-file.txt

real	0m2.344s
user	0m0.113s
sys	0m1.306s

$ time wc -l large-file.txt
5000000 large-file.txt

real	0m0.630s
user	0m0.092s
sys	0m0.537s 

wc -l命令背后的算法有什么建议和想法吗?

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-io

参考

如何处理 Struts 中的 404 错误

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/struts/how-to-handle-404-error-in-struts/

HTTP Status 404 ”错误代码表示系统找不到您请求的页面或资源。实际上,您应该显示自定义的 404 错误页面。但是,它是在 web.xml 中处理的,而不是在 Struts 框架中。举个例子,

 <web-app>
  ...
  <error-page>
    <error-code>404</error-code>
    <location>/pages/error404.jsp</location>
  </error-page>

</web-app> 

当系统遇到 404 错误时,它会转发到您自定义的 404 错误页面" /pages/error404.jsp "。

struts-config.xml

 <!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Maven Struts Examples</display-name>

  <servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>
        org.apache.struts.action.ActionServlet
    </servlet-class>
    <init-param>
        <param-name>config</param-name>
        <param-value>
         /WEB-INF/struts-config.xml
        </param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
       <servlet-name>action</servlet-name>
       <url-pattern>*.do</url-pattern>
  </servlet-mapping>

  <error-page>
    <error-code>404</error-code>
    <location>/pages/error404.jsp</location>
  </error-page>

</web-app> 

404 struts (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190309050027/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

如何用 jQuery 突出显示悬停时的表格行记录

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jquery/how-to-highlight-table-row-record-on-hover-with-jquery/

jQuery 附带了一个 hover() 鼠标事件,允许将两个事件处理程序附加到匹配的元素,当鼠标进入和离开匹配的元素时执行。

 $("#id").hover(A, B); 
  1. 当鼠标进入匹配的元素时调用的函数。
  2. b–当鼠标离开匹配的元素时调用的函数。

这是突出显示表格行记录的最佳功能。请参见 jQuery 代码片段:

 $("tr").not(':first').hover(
  function () {
    $(this).css("background","yellow");
  }, 
  function () {
    $(this).css("background","");
  }
); 

它将在悬停时突出显示表格行记录,颜色为黄色。。not(':first') "是避免突出显示标题行记录的常见实现。

你自己试试

 <html>
<head>

<script type="text/javascript" src="jquery-1.4.2.min.js"></script>
</head>
<body>
  <h1>Highlight table row record on hover - jQuery</h1>

  <table border="1">
    <tr><th>No</th><th>Name</th><th>Age</th><th>Salary</th></tr>
    <tr><td>1</td><td>Yong Mook Kim</td><td>28</td><td>$100,000</td></tr>
    <tr><td>2</td><td>Low Yin Fong</td><td>29</td><td>$90,000</td></tr>
    <tr><td>3</td><td>Ah Pig</td><td>18</td><td>$50,000</td></tr>
    <tr><td>4</td><td>Ah Dog</td><td>28</td><td>$40,000</td></tr>
    <tr><td>5</td><td>Ah Cat</td><td>28</td><td>$30,000</td></tr>
  </table>

<script type="text/javascript">

$("tr").not(':first').hover(
  function () {
    $(this).css("background","yellow");
  }, 
  function () {
    $(this).css("background","");
  }
);

</script>
</body>
</html> 

http://web.archive.org/web/20190214222705if_/http://www.mkyong.com/wp-content/uploads/jQuery/jQuery-highlight-table-row-record.html

Try Demohighlight jquery jquery effects table (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190214222705/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

如何在 JSF 中包含级联样式表(CSS)

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/how-to-include-cascading-style-sheets-css-in-jsf/

在 JSF 2.0 中,你可以使用<h:outputStylesheet />输出一个 css 文件。

举个例子,

 <h:outputStylesheet library="css" name="style.css"  /> 

它将生成以下 HTML 输出…

 <link type="text/css" rel="stylesheet" 
	href="/JavaServerFaces/faces/javax.faces.resource/style.css?ln=css" /> 

JSF 输出样式表示例

一个例子展示了使用 JSF 2 <h:outputStylesheet />渲染一个“style.css”文件,定位到“resources/css文件夹,见下图:

jsf2-outputStylesheet-example

JSF 文件

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html    
      xmlns:h="http://java.sun.com/jsf/html"
      >
    <h:head></h:head>
    <h:body>

    	<h1>JSF 2 outputStylesheet example</h1>

    	<h:outputStylesheet library="css" name="style.css"  />

    	<div class="red">This is red color</div>

    </h:body>

</html> 

它将生成以下 HTML 输出

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html >
	<head>
		<link type="text/css" rel="stylesheet" 
		  href="/JavaServerFaces/faces/javax.faces.resource/style.css?ln=css" />
	</head>

	<body>

    	   <h1>JSF 2 outputStylesheet example</h1>

    	   <div class="red">This is red color</div>

	</body>

</html> 

Warning
When render CSS file via <h:outputStylesheet /> tag, remember put the <h:head /> tag as well; Otherwise the css file will not be included.

下载源代码

Download It – JSF-2-outputStylesheet-Example.zip (9KB)

参考资料

  1. JSF < h:输出样式表/ > JavaDoc
  2. JSF2 resource library

标签:cssJSF 2

相关文章

jQuery-如何获取 CSS 类名为 an

如何在 JSF 中包含 JavaScript 文件

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/how-to-include-javascript-file-in-jsf/

在 JSF 2.0 中,你可以使用<h:outputScript />标签来呈现一个 HTML“脚本”元素,并将它链接到一个 js 文件。

举个例子,

 <h:outputScript library="js" name="common.js" /> 

它将生成以下 HTML 输出…

 <script type="text/javascript" 
  	src="/JavaServerFaces/faces/javax.faces.resource/common.js?ln=js">
</script> 

JSF 输出脚本示例

一个例子展示了如何使用<h:outputScript />来渲染一个common.js,见下图:

jsf2-outputScript-example

JSF 文件

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html    
      xmlns:h="http://java.sun.com/jsf/html"
      >
    <h:head></h:head>
    <h:body>

    	<h1>JSF 2 outputScript example</h1>

    	<h:outputScript library="js" name="common.js" />

    </h:body>
</html> 

它将生成以下 HTML 输出

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html >

   <head></head>

   <body>

     <h1>JSF 2 outputScript example</h1>

     <script type="text/javascript" 
       src="/JavaServerFaces/faces/javax.faces.resource/common.js?ln=js">
     </script>

   </body>
</html> 

JS 文件将呈现在放置 JSF <h:outputScript />标签的地方。

目标属性

此外,您可以使用“目标”属性来控制 js 文件的输出位置。

  1. target = " head "–显示在 HTML head 标签的顶部。
  2. target = " body "–显示在 body 标签的末尾。
  3. 无目标–显示在放置标签的位置。

例如

 <h:outputScript library="js" name="common.js" target="body" /> 

它将生成以下 HTML 输出

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html >

   <head>

   </head>

   <body> 	
     <h1>JSF 2 outputScript example</h1>

	<script type="text/javascript" 
	   src="/JavaServerFaces/faces/javax.faces.resource/common.js?ln=js">
	</script>
   </body>

</html> 

如何在 Windows 上安装 Apache Ant

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/ant/how-to-install-apache-ant-on-windows/

要在 Windows 上安装 Apache Ant ,你只需要下载 Ant 的 zip 文件,并解压,配置ANT_HOME Windows 环境变量。

使用的工具:

  1. JDK 1.7
  2. Apache Ant 1.9.4
  3. Windows 8.1

1.JAVA_HOME

确保安装了 JDK,并且将JAVA_HOME配置为 Windows 环境变量。

install-ant-on-windows-1

2.下载 Apache Ant

访问 Apache Ant 官网,下载 Ant 二进制 zip 文件,比如:apache-ant-1.9.4-bin.zip,解压到你想要存放 Apache Ant 的文件夹。

install-ant-on-windows-2

假设你解压到这个文件夹-C:\apache-ant-1.9.4

install-ant-on-windows-3

3.添加 ANT_HOME

添加ANT_HOME作为 Windows 环境变量,并将其指向您的 Ant 文件夹。

install-ant-on-windows-4

4.更新路径

更新PATH变量,在末尾追加%ANT_HOME%\bin,这样就可以到处运行蚂蚁的命令了。

install-ant-on-windows-5

5.确认

 C:\Users\mkyong>ant -v
Apache Ant(TM) version 1.9.4 compiled on April 29 2014
Trying the default build file: build.xml
Buildfile: build.xml does not exist!
Build failed 

如果您看到上面类似的消息,意味着 Apache Ant 已成功安装在 Windows 上。

参考

  1. 安装 Apache Ant

Tags : ant windows

如何为 Eclipse 安装谷歌插件

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/google-app-engine/how-to-install-google-plugin-for-eclipse/

在本教程中,我们将向您展示如何在 Eclipse 3.7 (Indigo)中安装“EclipseGoogle 插件”。

1.装置

在 Eclipse 3.7 中,点击“帮助”–>“安装新软件… 【T3”),复制粘贴以下网址:

 http://dl.google.com/eclipse/plugin/3.7 

Note
For other Eclipse version like 3.3, 3.4, 3.5, 3.6, please refer to this GAE Eclipse documentation.

图:选择“Google Plugin for Eclipse(必选),Google App Engine SDK for Java。

install google plugin for eclipse 3.7Note
The Google App Engine Java SDK is optional, you can download it together with the plugin, Or, download manually from GAE website and link it to “Google Plugin for Eclipse” later. ## 2.确认

等待几分钟安装进度,完成后,Eclipse 会提示您重新启动,单击 yes,Eclipse 的 Google 插件就安装好了。

图 Eclipse 工具栏中有一个小的 Google 图标。

instal googe plugin for eclipse 3.7 successDon’t use JRE 7
At this moment, don’t use JRE 7 runtime in Eclipse, it will caused the “Google Plugin for Eclipse” failed to install, and prompts you many “jar has been tampered” error message. See this thread. ## 参考

  1. https://developers . Google . com/app engine/docs/Java/tools/eclipse

gae google plugin install

如何在 Eclipse IDE 中安装 Hibernate / JBoss 工具

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/how-to-install-hibernate-tools-in-eclipse-ide/

Hibernate Tools 对于 Java 开发人员来说是一个方便的工具,可以用来生成乏味的 Hibernate 相关的东西,比如映射文件和注释代码。常见的用例是从数据库表生成 Hibernate 模型类、hbm 映射文件或注释代码的“逆向工程”特性。

Note
Hibernate Tools is bundled as the core component of JBoss Tools. So, after installed JBoss tools, you installed the Hibernate tools as well.

这里有一个指南向您展示如何在 Eclipse IDE 中安装 Hibernate / JBoss 工具。

1.了解要下载的 Eclipse & JBoss 工具版本

首先,您必须为您的 Eclipse IDE 找到正确版本的 Hibernate/JBoss 工具。点击此处-http://www.jboss.org/tools/download下载可用的组合版本。

举个例子,

  1. 如果您使用的是 Eclipse 3.6 / Helios,请下载 JBoss Tools 3.2
  2. 如果您使用的是 Eclipse 3.5 / Galileo,请下载 JBoss Tools 3.1

2.JBoss 工具的 Eclipse 更新站点

指向你的正确版本,右键复制 JBoss 工具的 Eclipse 更新站点。对于 Eclipse 3.6,URL 是“http://download.jboss.org/jbosstools/updates/stable/helios/

3.安装它

在 Eclipse IDE 的菜单栏中,选择“帮助”>”安装新软件… ,放入 Eclipse 更新站点的 URL。

JBoss tools in Eclipse

在过滤器框中键入“ hibernate ”,列出 hibernate 工具所需的组件。选择所有的 Hibernate Tools 组件,点击下一步下载。

JBoss tools in Eclipse 2Warning
Do not select all components, it will take much longer time download many unnecessary components. You want Hibernate tools only, not others.

4.重启 Eclipse

下载过程完成后,重启 Eclipse 以使其生效。

5.确认

如果 Hibernate tools 安装正确,您可以在窗口>>打开透视图>>其他中看到 Hibernate 透视图

Hibernate Perspective in Eclipse IDE

完成了。

参考

  1. http://www.hibernate.org/subprojects/tools.html
  2. http://www.jboss.org/tools/download

Tags : hibernate hibernate tools

相关文章

如何在 macOS 上安装 Java JDK

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-install-java-on-mac-osx/

本文展示了如何在 macOS 上安装 Java JDK,家酿软件包管理器,手动安装,以及在不同 JDK 版本之间切换。

测试对象

  • 马斯科 11 号
  • 自制软件 2.7.4
  • JDK 8,14,16,16(采用 OpenJDK 和 OpenJDK)

主题

  1. 自制在 macOS 上安装最新的 Java(open JDK)
  2. 自制在 macOS 上安装 Java 8(open JDK)
  3. 家酿在 macOS 上安装指定的 Java(AdoptOpenJDK)
  4. 在 macOS 上手动安装 Java(早期版本)
  5. 在不同的 JDK 版本之间切换

在撰写本文时,最新的 JDK GA 是 JDK 15,早期的访问版本是 JDK 16。

注意
从 macOS 10.15 Catalina 开始,默认终端 shell 从 bash (Bourne-again shell)切换到 zsh (Z shell)。我们应该将~/.bash_profile~/.bashrc中的所有启动脚本和环境变量移到~/.zshenv~/.zshrc

还有,读这个 Zsh 启动文件

1。自制软件在 macOS 上安装最新的 Java

1.1 安装和升级自制软件

1.2 brew search java查找所有可用的 Java 相关公式。

Terminal

 % brew search java      

==> Formulae
app-engine-java           java                      javacc                    jslint4java               pdftk-java
google-java-format        java11                    javarepl                  libreadline-java 

1.3 brew info显示配方详情。

java公式总是包含最新的 Java JDK (OpenJDK) GA 版本;在撰写本文时,最新的 GA 是 JDK 15。

Terminal

 % brew info java

openjdk: stable 15.0.1 (bottled) [keg-only]
Development kit for the Java programming language
https://openjdk.java.net/
/usr/local/Cellar/openjdk/15.0.1 (614 files, 324.9MB)
  Poured from bottle on 2020-12-09 at 09:06:07
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/openjdk.rb
License: Cannot Represent 

java11公式包含 Java 11 LTS 版本。

Terminal

 % brew info java11  

openjdk@11: stable 11.0.9 (bottled) [keg-only]
Development kit for the Java programming language
https://openjdk.java.net/
Not installed
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/openjdk@11.rb
License: GPL-2.0-only 

1.4 brew install java安装最新的 JDK 15。

Terminal

 % brew info java 

1.5 家酿在哪里安装 java?
家酿在/usr/local/Cellar/openjdk/安装了 JDK 文件和目录,/usr/local/opt/openjdk的符号链接指向最新的 Java 15.0.1版本。

Terminal

 % ls -lsa /usr/local/Cellar/openjdk/      

total 0
0 drwxr-xr-x   3 mkyong  staff    96 Dec  9 09:06 .
0 drwxrwxr-x  69 mkyong  admin  2208 Jan 15 15:35 ..
0 drwxr-xr-x   9 mkyong  staff   288 Jan 15 16:47 15.0.1

% ls -lsa /usr/local/opt/openjdk
0 lrwxr-xr-x  1 mkyong  admin  24 Dec  9 09:06 /usr/local/opt/openjdk -> ../Cellar/openjdk/15.0.1 

1.6java配方为桶专用,即安装在/usr/local/Cellar但不链接到/usr/local/bin/Library/Java/JavaVirtualMachines/等地(macOS /usr/bin/java包装)。

为了让 macOS /usr/bin/java包装器找到已安装的 JDK,我们在/Library/Java/JavaVirtualMachines/手动创建一个符号链接。

Terminal

 % sudo ln -sfn /usr/local/opt/openjdk/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk.jdk 

1.7 搞定。

Terminal

 % java -version

openjdk version "15.0.1" 2020-10-20
OpenJDK Runtime Environment (build 15.0.1+9)
OpenJDK 64-Bit Server VM (build 15.0.1+9, mixed mode, sharing) 

2。自制在 macOS 上安装 Java 8

2.1 安装并升级自制软件

2.2brew search java没有java8

Terminal

 % brew search java        
==> Formulae
app-engine-java           java                      javacc                    jslint4java               pdftk-java
google-java-format        java11                    javarepl                  libreadline-java 

2.3 Java 8 在openjdk@8公式处可用。openjdkjava公式一样,总是包含最新的 JDK GA 版本;openjdk@11java11公式相同,包含 JDK 11。

Terminal

 % brew search openjdk
==> Formulae
openjdk                                   openjdk@11                                  openjdk@8 

2.4 我们可以使用openjdk@8公式在 macOS 上安装 Java 8。

Terminal

 % brew install openjdk@8 

2.5openjdk@8也是专用桶;我们需要创建一个符号链接,以便 macOS java包装器能够找到它。

Terminal

 % sudo ln -sfn /usr/local/opt/openjdk@8/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-8.jdk 

2.6 搞定。

Terminal

 % java -version

openjdk version "1.8.0_275"
OpenJDK Runtime Environment (build 1.8.0_275-bre_2020_11_16_15_09-b00)
OpenJDK 64-Bit Server VM (build 25.275-b00, mixed mode) 

2.7 如果我们安装了多个 Java 版本会怎样?

Terminal

 ls -lsah /Library/Java/JavaVirtualMachines/               

openjdk-8.jdk -> /usr/local/opt/openjdk@8/libexec/openjdk.jdk
openjdk.jdk -> /usr/local/opt/openjdk/libexec/openjdk.jdk 

我们可以在~/.zshrc更新$PATH,这样 macOS 就可以找到正确安装的 Java。

Terminal

 % java -version

openjdk version "15.0.1" 2020-10-20
OpenJDK Runtime Environment (build 15.0.1+9)
OpenJDK 64-Bit Server VM (build 15.0.1+9, mixed mode, sharing)

% echo 'export PATH="/usr/local/opt/openjdk@8/bin:$PATH"' >> ~/.zshrc  

% source ~/.zshrc

% java -version

openjdk version "1.8.0_275"
OpenJDK Runtime Environment (build 1.8.0_275-bre_2020_11_16_15_09-b00)
OpenJDK 64-Bit Server VM (build 25.275-b00, mixed mode) 

**JAVAHOMEmacOS[JAVA_HOME`环境变量。](/web/20221225035418/https://mkyong.com/java/how-to-set-java_home-environment-variable-on-mac-os-x/)

3。家酿在 macOS 上安装指定的 Java (AdoptOpenJDK)。

adoptopenjdk/openjdk tap 包含了很多不同的 JDK (AdoptOpenJDK)版本。

3.1 新增tap(第三方库)adoptopenjdk/openjdk

Terminal

 % brew tap adoptopenjdk/openjdk 

3.2 搜索相关的adoptopenjdk公式。

Terminal

 % brew search adoptopenjdk

==> Casks
adoptopenjdk                              adoptopenjdk12-openj9                     adoptopenjdk14-openj9-large
adoptopenjdk-jre                          adoptopenjdk12-openj9-jre                 adoptopenjdk15
adoptopenjdk-openj9                       adoptopenjdk12-openj9-jre-large           adoptopenjdk15-jre
adoptopenjdk-openj9-jre                   adoptopenjdk12-openj9-large               adoptopenjdk15-openj9
adoptopenjdk-openj9-jre-large             adoptopenjdk13                            adoptopenjdk15-openj9-jre
adoptopenjdk-openj9-large                 adoptopenjdk13-jre                        adoptopenjdk15-openj9-jre-large
adoptopenjdk10                            adoptopenjdk13-openj9                     adoptopenjdk15-openj9-large
adoptopenjdk11                            adoptopenjdk13-openj9-jre                 adoptopenjdk8
adoptopenjdk11-jre                        adoptopenjdk13-openj9-jre-large           adoptopenjdk8
adoptopenjdk11-openj9                     adoptopenjdk13-openj9-large               adoptopenjdk8-jre
adoptopenjdk11-openj9-jre                 adoptopenjdk14                            adoptopenjdk8-openj9
adoptopenjdk11-openj9-jre-large           adoptopenjdk14-jre                        adoptopenjdk8-openj9-jre
adoptopenjdk11-openj9-large               adoptopenjdk14-openj9                     adoptopenjdk8-openj9-jre-large
adoptopenjdk12                            adoptopenjdk14-openj9-jre                 adoptopenjdk8-openj9-large
adoptopenjdk12-jre                        adoptopenjdk14-openj9-jre-large           adoptopenjdk9 

3.3 我们选择adoptopenjdk14公式来安装 JDK 14。

Terminal

 % brew install adoptopenjdk14

installer: Package name is AdoptOpenJDK
installer: Installing at base path /
installer: The install was successful.
package-id: net.adoptopenjdk.14.jdk
version: 14.0.2+12
volume: /
location: Library/Java/JavaVirtualMachines/adoptopenjdk-14.jdk
install-time: 1610720586
adoptopenjdk14 was successfully installed! 

3.4adoptopenjdk公式直接在/Library/Java/JavaVirtualMachines/中创建 JDK 家。

Terminal

 % ls -lsa /Library/Java/JavaVirtualMachines/

adoptopenjdk-14.jdk
openjdk-8.jdk -> /usr/local/opt/openjdk@8/libexec/openjdk.jdk
openjdk.jdk -> /usr/local/opt/openjdk/libexec/openjdk.jdk 

3.5 由于 JDK 家已经在/Library/Java/JavaVirtualMachines/中,我们不需要创建任何符号链接,只需导出$PATH并指向正确的adoptopenjdk-14.jdk

Terminal

 % echo 'export PATH="/Library/Java/JavaVirtualMachines/adoptopenjdk-14.jdk/Contents/Home/bin:$PATH"' >> ~/.zshrc

% source ~/.zshrc

% java -version
openjdk version "14.0.2" 2020-07-14
OpenJDK Runtime Environment AdoptOpenJDK (build 14.0.2+12)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 14.0.2+12, mixed mode, sharing) 


也读这个切换 adoptopenjdk 桶使用 pkg #73145

4。在 macOS 上手动安装 Java(早期版本)。

出于某些原因,我们需要在 macOS 上手动安装 Java:

  • 反自制,开发者爱控制一切。
  • JDK 版本不存在于自制软件库中,不像早期访问版本或甲骨文 JDK。

在撰写本文时,JDK 早期使用的版本是 JDK 16 号。

4.1 访问 JDK 16 早期访问构建网站并下载 JDK。

install jdk16 on macOS

4.2 将下载的tar.gz文件提取到/Library/Java/JavaVirtualMachines

Terminal

 % sudo tar xvzf ~/Downloads/openjdk-16-ea+32_osx-x64_bin.tar.gz -C /Library/Java/JavaVirtualMachines

% ls -lsa /Library/Java/JavaVirtualMachines

adoptopenjdk-14.jdk
jdk-16.jdk
openjdk-8.jdk -> /usr/local/opt/openjdk@8/libexec/openjdk.jdk
openjdk.jdk -> /usr/local/opt/openjdk/libexec/openjdk.jdk 

4.3 更新$PATH并指向/Library/Java/JavaVirtualMachines/jdk-16.jdk

Terminal

 % echo 'export PATH="/Library/Java/JavaVirtualMachines/jdk-16.jdk/Contents/Home/bin:$PATH"' >> ~/.zshrc 

4.4 测试 JDK 16。

Terminal

 % source ~/.zshrc

% java -version
openjdk version "16-ea" 2021-03-16
OpenJDK Runtime Environment (build 16-ea+32-2190)
OpenJDK 64-Bit Server VM (build 16-ea+32-2190, mixed mode, sharing) 

完成了。

5。在不同的 JDK 版本之间切换

从上面的例子 1 到例子 4,我们已经在 macOS 上安装了四个 JDK 版本。

5.1 列出 macOS 上的所有 JDK 版本。

Terminal

 % /usr/libexec/java_home -V

Matching Java Virtual Machines (4):
  16 (x86_64) "Oracle Corporation" - "OpenJDK 16-ea" /Library/Java/JavaVirtualMachines/jdk-16.jdk/Contents/Home
  15.0.1 (x86_64) "UNDEFINED" - "OpenJDK 15.0.1" /usr/local/Cellar/openjdk/15.0.1/libexec/openjdk.jdk/Contents/Home
  14.0.2 (x86_64) "AdoptOpenJDK" - "AdoptOpenJDK 14" /Library/Java/JavaVirtualMachines/adoptopenjdk-14.jdk/Contents/Home
  1.8.0_275 (x86_64) "UNDEFINED" - "OpenJDK 8" /usr/local/Cellar/openjdk@8/1.8.0+275/libexec/openjdk.jdk/Contents/Home
/Library/Java/JavaVirtualMachines/jdk-16.jdk/Contents/Home

% ls -lsa /Library/Java/JavaVirtualMachines

adoptopenjdk-14.jdk
jdk-16.jdk
openjdk-8.jdk -> /usr/local/opt/openjdk@8/libexec/openjdk.jdk
openjdk.jdk -> /usr/local/opt/openjdk/libexec/openjdk.jdk 

5.2 在~/.zshrc(MAC OS 10.15 Catalina 及以上)或~/.bashrc(MAC OS 10.15 Catalina 之前)中增加以下功能。

~/.zshrc

 jdk() {
      version=$1
      unset JAVA_HOME;
      export JAVA_HOME=$(/usr/libexec/java_home -v"$version");
      java -version
} 

如果文件~/.zshrc不存在,创建它。

5.3 生成~/.zshrc以反映变化。

Terminal

 % source ~/.zshrc 

5.4 在不同的 JDK 版本之间切换。

Terminal

 % java -version
openjdk version "16-ea" 2021-03-16
OpenJDK Runtime Environment (build 16-ea+32-2190)
OpenJDK 64-Bit Server VM (build 16-ea+32-2190, mixed mode, sharing)

% jdk 1.8
openjdk version "1.8.0_275"
OpenJDK Runtime Environment (build 1.8.0_275-bre_2020_11_16_15_09-b00)
OpenJDK 64-Bit Server VM (build 25.275-b00, mixed mode)

% jdk 14
openjdk version "14.0.2" 2020-07-14
OpenJDK Runtime Environment AdoptOpenJDK (build 14.0.2+12)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 14.0.2+12, mixed mode, sharing)

% jdk 15
openjdk version "15.0.1" 2020-10-20
OpenJDK Runtime Environment (build 15.0.1+9)
OpenJDK 64-Bit Server VM (build 15.0.1+9, mixed mode, sharing)

% jdk 16
openjdk version "16-ea" 2021-03-16
OpenJDK Runtime Environment (build 16-ea+32-2190)
OpenJDK 64-Bit Server VM (build 16-ea+32-2190, mixed mode, sharing) 

延伸阅读
如何在 macOS 上设置 $JAVA_HOME环境变量。

参考文献

如何在 Ubuntu 上安装 Maven

原文:http://web.archive.org/web/20230101150211/https://www.mkyong.com/maven/how-to-install-maven-in-ubuntu/

在本教程中,我们将向您展示如何在 Ubuntu 上安装 Apache Maven。

测试对象

  1. Maven 3.5.2
  2. Ubuntu 18.04

Note
Before the Maven installation, make sure JDK is installed and JAVA_HOME is configured.

1.搜索专家

查看本地存储库中的 Maven 包版本。

 $ sudo apt policy maven

maven:
  Installed: (none)
  Candidate: 3.5.2-2
  Version table:
     3.5.2-2 500
        500 http://my.archive.ubuntu.com/ubuntu bionic/universe amd64 Packages
        500 http://my.archive.ubuntu.com/ubuntu bionic/universe i386 Packages 

是 Maven 3.5.2。

2.安装 Maven

通过apt命令安装 Maven。

 $ sudo apt install maven

Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  libaopalliance-java libapache-pom-java libatinject-

//...

Setting up libsisu-inject-java (0.3.2-2) ...
Setting up libsisu-plexus-java (0.3.3-3) ...
Setting up libmaven3-core-java (3.5.2-2) ...
Setting up maven (3.5.2-2) ...
update-alternatives: using /usr/share/maven/bin/mvn to provide /usr/bin/mvn (mvn) in auto mode 

3.确认

Apache Maven 3.5.2 安装成功。

 $ mvn -version

Apache Maven 3.5.2
Maven home: /usr/share/maven
Java version: 11.0.1, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-11-oracle
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "4.15.0-38-generic", arch: "amd64", family: "unix" 

4.玛文在哪里?

apt命令在以下位置安装了 Maven:

 $ ls -lsa /usr/share/maven
total 32
 4 drwxr-xr-x   6 root root  4096 Nov   9 17:34 .
12 drwxr-xr-x 227 root root 12288 Nov   9 17:34 ..
 4 drwxr-xr-x   2 root root  4096 Nov   9 17:34 bin
 4 drwxr-xr-x   2 root root  4096 Nov   9 17:34 boot
 0 lrwxrwxrwx   1 root root    10 Feb  24  2018 conf -> /etc/maven
 4 drwxr-xr-x   2 root root  4096 Nov   9 17:34 lib
 4 drwxr-xr-x   2 root root  4096 Nov   9 17:34 man

$ ls -lsa /etc/maven
total 40
 4 drwxr-xr-x   3 root root  4096 Nov   9 17:34 .
12 drwxr-xr-x 127 root root 12288 Nov   9 17:34 ..
 4 drwxr-xr-x   2 root root  4096 Nov   9 17:34 logging
 4 -rw-r--r--   1 root root   220 Okt  18  2017 m2.conf
12 -rw-r--r--   1 root root 10211 Okt  18  2017 settings.xml
 4 -rw-r--r--   1 root root  3645 Okt  18  2017 toolchains.xml 

参考

  1. 如何在 Ubuntu 上安装 Java JDK

如何在 Windows 上安装 Maven

原文:http://web.archive.org/web/20230101150211/https://www.mkyong.com/maven/how-to-install-maven-in-windows/

要在 Windows 上安装 Apache Maven ,您只需要下载 Maven 的 zip 文件,将其解压缩到一个文件夹中,并配置 Windows 环境变量。

测试对象:

  1. JDK 10
  2. Maven 3.6
  3. Windows 10

Note

  1. Maven 3.3+需要 JDK 1.7+版本
  2. Maven 3.2 需要 JDK 1.6 以上版本
  3. Maven 3.0/3.1 需要 JDK 1.5 以上版本

1.JDK 和 JAVA_HOME

确保安装了 JDK,并且配置了JAVA_HOME环境变量。

Note
Please read this how to add JAVA_HOME on Windows 10

2.下载 Apache Maven

2.1 访问 Maven 官网,下载 Maven zip 文件,例如:apache-maven-3.6.0-bin.zip

2.2 解压到一个文件夹。在本文中,我们使用c:\opt\apache-maven-3.6.0

Note
That’s all, just download and unzip, installation is NOT required.

3.添加 MAVEN_HOME 系统变量

添加一个MAVEN_HOME系统变量,并将其指向 Maven 文件夹。

3.1 按 Windows 键,键入adva并点击View advanced system settings

3.2 在系统属性对话框中,选择Advanced选项卡并点击Environment Variables...按钮。

3.3 在“环境变量”对话框中,System variables,点击New...按钮,添加一个MAVEN_HOME变量并指向c:\opt\apache-maven-3.6.0

4.将%MAVEN_HOME%\bin 添加到路径

在系统变量中,找到PATH,点击Edit...按钮。在“编辑环境变量”对话框中,点击New按钮并添加此%MAVEN_HOME%\bin

5.确认

完成后,启动一个新的命令提示符,键入mvn –version:

 C:\Users\mkyong>mvn -version
Apache Maven 3.6.0 (97c98ec64a1fdfee7767ce5ffb20918da4f719f3; 2018-10-25T02:41:47+08:00)
Maven home: C:\opt\apache-maven-3.6.0\bin\..
Java version: 10.0.1, vendor: Oracle Corporation, runtime: C:\opt\Java\jdk-10
Default locale: en_MY, platform encoding: Cp1252
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"

C:\Users\mkyong>echo %MAVEN_HOME%
C:\opt\apache-maven-3.6.0 

Apache Maven 已成功安装在 Windows 上。

6.常见问题

6.1“mvn”不被识别为内部或外部命令?

 > mvn -version
'mvn' is not recognized as an internal or external command,
operable program or batch file. 

答:参考步骤 4,确保%MAVEN_HOME%\bin被添加到PATH系统变量中。

6.2 未正确定义 JAVA_HOME 环境变量

 > mvn -version
The JAVA_HOME environment variable is not defined correctly
This environment variable is needed to run this program
NB: JAVA_HOME should point to a JDK not a JRE 

答:参考步骤 2,确保安装了 JDK,并且配置了JAVA_HOME系统变量。

参考

  1. 如何在 Windows 10 上添加 JAVA _ HOME

如何在 Mac OS X 上安装 MongoDB

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/mongodb/how-to-install-mongodb-on-mac-os-x/

向您展示如何在 Mac OS X 上安装 MongoDB 的指南。

  1. MongoDB 2.2.3
  2. 麦克 OS X 10.8.2

1.下载 MongoDB

官网获取 MongoDB,摘录:

 $ cd ~/Download
$ tar xzf mongodb-osx-x86_64-2.2.3.tgz
$ sudo mv mongodb-osx-x86_64-2.2.3 /usr/local/mongodb 

2. MongoDB Data

默认情况下,MongoDB 将数据写入/存储到/data/db文件夹中,您需要手动创建这个文件夹并分配适当的权限。

 $ sudo mkdir -p /data/db
$ whoami
mkyong
$ sudo chown mkyong /data/db 

Note
Permissin is required to avoid following locking error :

 Unable to create/open lock file: /data/db/mongod.lock 

3.将 mongodb/bin 添加到 PATH

创建一个~/.bash_profile文件并将/usr/local/mongodb/bin分配给 $PATH 环境变量,这样就可以轻松访问 Mongo 的命令。

 $ cd ~
$ pwd
/Users/mkyong
$ touch .bash_profile
$ vim .bash_profile

export MONGO_PATH=/usr/local/mongodb
export PATH=$PATH:$MONGO_PATH/bin

##restart terminal

$ mongo -version
MongoDB shell version: 2.2.3 

4.启动 MongoDB

mongod启动 MongoDB,用mongo做一个简单的 mongo 连接。

Terminal 1

 $ mongod
MongoDB starting : pid=34022 port=27017 dbpath=/data/db/ 64-bit host=mkyong.local
//...
waiting for connections on port 27017 

Terminal 2

 $ mongo
MongoDB shell version: 2.2.3
connecting to: test
> show dbs
local	(empty) 

Note
If you don’t like the default /data/db folder, just specify an alternate path with --dbpath

 $ mongod --dbpath /any-directory 

5.自动启动 MongoDB

要自动启动 mongoDB,请在 Mac 上创建一个启动作业。

 $ sudo vim /Library/LaunchDaemons/mongodb.plist 

放入以下内容:

/Library/LaunchDaemons/mongodb.plist

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>mongodb
  <key>ProgramArguments</key>
  <array>
    <string>/usr/local/mongodb/bin/mongod
  </array>
  <key>RunAtLoad</key>
  <true/>
  <key>KeepAlive</key>
  <true/>
  <key>WorkingDirectory</key>
  <string>/usr/local/mongodb
  <key>StandardErrorPath</key>
  <string>/var/log/mongodb/error.log
  <key>StandardOutPath</key>
  <string>/var/log/mongodb/output.log
</dict>
</plist> 

高于工作负荷。

 $ sudo launchctl load /Library/LaunchDaemons/mongodb.plist

$ ps -ef | grep mongo
    0    71     1   0  1:50PM ??         0:22.26 /usr/local/mongodb/bin/mongod
  501   542   435   0  2:23PM ttys000    0:00.00 grep mongo 

尝试重启你的 Mac,MongoDB 会自动启动。

参考

  1. mongoDB 网站
  2. 在 Mac OS X 上安装 mongoDB
  3. launchd.plist 示例
  4. 在 Mac OS X 上设计守护进程
  5. Mac 启动示例

如何在 Ubuntu 上安装 mongoDB

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/mongodb/how-to-install-mongodb-on-ubuntu/

mongodb-ubuntu

本指南向您展示了如何在 Ubuntu 上安装 MongoDB。

  1. Ubuntu 12.10
  2. MongoDB 2.2.3

1.将 10gen 包添加到 source.list.d

Ubuntu 12 自带“mongo”包,但不是最新版本。

 $ sudo apt-cache search mongodb
mongodb
mongodb-clients
mongodb-dev
mongodb-server 

建议给/etc/apt/sources.list.d加 10gen 包,因为里面有最新稳定的 MongoDB。创建一个/etc/apt/sources.list.d/mongo.list文件,并声明 10gen 发行版。

 $ sudo vim /etc/apt/sources.list.d/mongo.list 

/etc/apt/sources.list.d/mongo.list

 ##10gen package location

deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen 

2.添加 GPG 键

第 10 代产品包需要 GPG 密钥,将其导入:

 $ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 7F0CEB10 

如果您没有导入 GPG 键,apt-get update将会显示以下错误信息:

 GPG error: http://downloads-distro.mongodb.org dist Release: 
The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 9ECBEC467F0CEB10 

3.更新包

更新您的apt-get列表。

 $ sudo apt-get update 

再次搜索“mongodb”,现在出现了新的 10gen 包。获取“mongodb-10gen”,它包含了最新稳定的 MongoDB。

 $ sudo apt-cache search mongodb
mongodb
mongodb-clients
mongodb-dev
mongodb-server

mongodb-10gen
mongodb18-10gen
mongodb20-10gen 

4.安装 mongodb-10gen

一切准备就绪,现在您可以安装 MongoDB:

 $ sudo apt-get install mongodb-10gen 

5.MongoDB 在哪里?

MongoDB 已安装并启动。

 $ ps -ef | grep mongo
mongodb   5262     1  0 15:27 ?        00:00:14 /usr/bin/mongod --config /etc/mongodb.conf
mkyong    5578  3994  0 16:29 pts/0    00:00:00 grep --color=auto mongo

$ mongo -version
MongoDB shell version: 2.2.3 

所有的 MongoDB 可执行文件都存储在/usr/bin/

 $ ls -ls /usr/bin | grep mongo
 4220 -rwxr-xr-x 1 root   root     4317928 Feb  2 08:11 mongo
10316 -rwxr-xr-x 1 root   root    10563336 Feb  2 08:11 mongod
10320 -rwxr-xr-x 1 root   root    10563664 Feb  2 08:11 mongodump
10284 -rwxr-xr-x 1 root   root    10526736 Feb  2 08:11 mongoexport
10324 -rwxr-xr-x 1 root   root    10567768 Feb  2 08:11 mongofiles
10296 -rwxr-xr-x 1 root   root    10539056 Feb  2 08:11 mongoimport
10272 -rwxr-xr-x 1 root   root    10514544 Feb  2 08:11 mongooplog
10272 -rwxr-xr-x 1 root   root    10518512 Feb  2 08:11 mongoperf
10320 -rwxr-xr-x 1 root   root    10563632 Feb  2 08:11 mongorestore
 6644 -rwxr-xr-x 1 root   root     6802848 Feb  2 08:11 mongos
10312 -rwxr-xr-x 1 root   root    10556560 Feb  2 08:11 mongostat
10272 -rwxr-xr-x 1 root   root    10515856 Feb  2 08:11 mongotop 

“mongodb 控制脚本”在/etc/init.d/mongodb生成

 $ ls -ls /etc/init.d | grep mongo
 0 lrwxrwxrwx 1 root root   21 Feb  2 08:11 mongodb -> /lib/init/upstart-job 

MongoDB 配置文件位于/etc/mongodb.conf

/etc/mongodb.conf

 # mongodb.conf

# Where to store the data.

# Note: if you run mongodb as a non-root user (recommended) you may
# need to create and set permissions for this directory manually,
# e.g., if the parent directory isn't mutable by the mongodb user.
dbpath=/var/lib/mongodb

#where to log
logpath=/var/log/mongodb/mongodb.log

logappend=true

#port = 27017

#...... 

6.控制 MongoDB

一些控制 MongoDB 的命令。

正在启动 MongoDB

 $ sudo service mongodb start 

停止 mongodb

 $ sudo service mongodb stop 

重新启动 MongoDB

 $ sudo service mongodb restart 

参考

  1. 在 Ubuntu 上安装 MongoDB 的官方指南
  2. Debian Linux apt-get 包管理备忘单
  3. 在 Mac OS X 上安装 MongoDB
  4. 在 Windows 上安装 MongoDB

如何在 Windows 上安装 MongoDB

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/mongodb/how-to-install-mongodb-on-windows/

在本教程中,我们将向您展示如何在 Windows 上安装 MongoDB

  1. MongoDB 2.2.3
  2. Windows 7

Note
The MongoDB does not require installation, just download and extracts the zip file, configure the data directory and start it with command “mongod“.

1.下载 MongoDB

从官方 MongoDB 网站下载 MongoDB。选择 Windows 32 位或 64 位。解压,解压到你喜欢的位置,例如:d:\mongodb\

2.查看 MongoDB 文件夹

在 MongoDB 中,它在 bin 文件夹中只包含 10+个可执行文件(exe)。这是真的,这是 MongoDB 所需的文件,对于像我这样来自关系数据库背景的开发人员来说,这真的很难相信。

图:$MongoDB/bin 文件夹下的文件

mongodb-windowsNote
It’s recommended to add $MongoDB/bin to Windows environment variable, so that you can access the MongoDB’s commands in command prompt easily.

3.配置文件

创建一个 MongoDB 配置文件,它只是一个文本文件,例如:d:\mongodb\mongo.config

d:\mongodb\mongo.config

 ##store data here
dbpath=D:\mongodb\data

##all output go here
logpath=D:\mongodb\log\mongo.log

##log read and write operations
diaglog=3 

Note
MongoDB need a folder (data directory) to store its data. By default, it will store in “C:\data\db“, create this folder manually. MongoDB won’t create it for you. You can also specify an alternate data directory with --dbpath option.

4.运行 MongoDB 服务器

使用mongod.exe --config d:\mongodb\mongo.config启动 MongoDB 服务器。

 d:\mongodb\bin>mongod --config D:\mongodb\mongo.config
all output going to: D:\mongodb\log\mongo.log 

5.连接到 MongoDB

使用mongo.exe连接到启动的 MongoDB 服务器。

 d:\mongodb\bin>mongo
MongoDB shell version: 2.2.3
connecting to: test
> //mongodb shell 

6.MongoDB 作为 Windows 服务

将 MongoDB 添加为 Windows 服务,这样 MongoDB 将在每次系统重启后自动启动。

使用--install安装为 Windows 服务。

 d:\mongodb\bin> mongod --config D:\mongodb\mongo.config --install 

一个名为“MongoDB”的 Windows 服务被创建。

mongodb-windows-service

要启动 MongoDB 服务

 net start MongoDB 

停止 MongoDB 服务

 net stop MongoDB 

删除 MongoDB 服务

 d:\mongodb\bin>mongod --remove 

7.常见问题

1.在 Windows 8 上安装 MongoDB 作为 Windows 服务,但点击“访问被拒绝。”错误消息:

 C:\Users\mkyong2002>mongod --config D:\mongodb\mongo.config --install
Tue Jul 16 21:05:55.154 diagLogging level=3
Tue Jul 16 21:05:55.155 diagLogging using file D:\mongodb\data/diaglog.51e54533
Tue Jul 16 21:05:55.155 Trying to install Windows service 'MongoDB'
Tue Jul 16 21:05:55.155 Error connecting to the Service Control Manager: Access
is denied. (5) 

要修复它,请使用管理权限运行命令提示符——右键单击命令提示符图标,选择以管理员身份运行。

参考

  1. 在 Windows 上安装 MongoDB
  2. MongoDB 配置选项

如何在 CentOS 上安装 Oracle JDK 8

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-install-oracle-jdk-8-on-centos/

java8-centos-example

在本教程中,我们将向您展示如何在 CentOS 上安装 Oracle JDK 8。

环境:

  1. 厘斯 6.8
  2. 甲骨文 JDK 8u102

Note
This guide should work on Fedora and RedHat.

1.获取甲骨文 JDK 8

1.1 访问甲骨文 JDK 下载页面,寻找RPM版本。

1.2 复制jdk-8u102-linux-x64.rpmwget的下载链接。

 $ pwd
/home/mkyong

$ wget --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u102-b14/jdk-8u102-linux-x64.rpm 

2.安装 Oracle JDK 8

2.1 用yum localinstall安装。

 $ sudo yum localinstall jdk-8u102-linux-x64.rpm

//...
//...
//...
Installed:
  jdk1.8.0_102.x86_64 2000:1.8.0_102-fcs                                                                                                                                          

Complete! 

2.2 现在 JDK 应该安装在/usr/java/jdk1.8.0_102

 $ cd /usr/java
$ ls -lsah
total 12K
4.0K drwxr-xr-x   3 root root 4.0K Jul 21 09:58 ./
4.0K drwxr-xr-x. 15 root root 4.0K Jun 22 22:00 ../
   0 lrwxrwxrwx   1 root root   16 Jul 21 09:58 default -> /usr/java/latest/
4.0K drwxr-xr-x   9 root root 4.0K Jul 21 09:58 jdk1.8.0_102/
   0 lrwxrwxrwx   1 root root   22 Jul 21 09:58 latest -> /usr/java/jdk1.8.0_102/ 

2.3 验证

 $ java -version
java version "1.8.0_102"
Java(TM) SE Runtime Environment (build 1.8.0_102-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.102-b14, mixed mode) 

2.4 删除 RPM 文件

 $ rm ~/jdk-8u102-linux-x64.rpm 

完成了。Oracle JDK 8 成功安装在 CentOS 上。

3.JAVA_HOME 环境变量

这是设置环境变量JAVA_HOME的好方法。

3.1 编辑.bash_profile,在文件末尾追加export JAVA_HOME,例如:

.bash_profile

 # Get the aliases and functions
if [ -f ~/.bashrc ]; then
	. ~/.bashrc
fi

# User specific environment and startup programs

export JAVA_HOME=/usr/java/jdk1.8.0_102/
export JRE_HOME=/usr/java/jdk1.8.0_102/jre

PATH=$PATH:$HOME/bin:$JAVA_HOME/bin

export PATH 

3.2 测试$JAVA_HOME$PATH

 $ source .bash_profile 

$ echo $JRE_HOME
/usr/java/jdk1.8.0_102/jre

$ echo $JAVA_HOME
/usr/java/jdk1.8.0_102/

$ echo $PATH
/...:/usr/local/bin:/usr/X11R6/bin:/home/mkyong/bin:/usr/java/jdk1.8.0_102//bin 

4.安装了多个 JDK

如果 CentOS 安装了多个 JDK,您可以使用alternatives命令设置默认的java

 $ sudo alternatives --config java
[sudo] password for mkyong: 

There are 2 programs which provide 'java'.

  Selection    Command
-----------------------------------------------
   1           /usr/lib/jvm/jre-1.6.0-openjdk.x86_64/bin/java
*+ 2           /usr/java/jdk1.8.0_102/jre/bin/java

Enter to keep the current selection[+], or type selection number: 

参考

  1. 如何在 Debian 上安装 Oracle JDK 8
  2. 如何在 CentOS 和 Fedora 上安装 Java
  3. 如何在 Linux 或 CentOS 中设置 JAVA 环境变量
  4. 如何使用‘alternatives’命令在 CentOS/RHEL 和 Fedora 上安装 Java 8
  5. Fedora、Redhat 和 CentOS 的区别

Tags : CentOS fedora install-java java8 RedHat

如何在 Debian 上安装 Oracle JDK 8

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-install-oracle-jdk-8-on-debian/

java8-debian

在本教程中,我们将向您展示如何在 Debian 上手动安装 Oracle JDK 8。

环境:

  1. Debian 7
  2. 已安装 OpenJDK 1.7。(稍后切换到甲骨文 JDK 8)

在撰写本文时,OpenJDK 1.8 还没有包含在默认的 apt-get 存储库中。我只是不喜欢默认的 apt 库时间表,它总是伴随着旧的或过时的版本。

Note
This guide is tested in other Debian derivatives like Ubuntu 14 and Mint 1.7.2.

1.快速检查

1.1 快速 Java 版本检查:

 $ java -version
java version "1.7.0_75"
OpenJDK Runtime Environment (IcedTea 2.5.4) (7u75-2.5.4-1~deb7u1)
OpenJDK 64-Bit Server VM (build 24.75-b04, mixed mode)

$ javac -version
javac 1.7.0_75 

安装了一个现有的 OpenJDK 1.7,没问题,我们会告诉你如何切换到 JDK 8。

1.2 通过apt-cache快速搜索,目前还没有 openjdk-8…的。

 $ apt-cache search openjdk

...
openjdk-7-jre - OpenJDK Java runtime, using Hotspot JIT
openjdk-7-jre-headless - OpenJDK Java runtime, using Hotspot JIT (headless)
openjdk-6-jre - OpenJDK Java runtime, using Hotspot JIT
openjdk-6-jre-headless - OpenJDK Java runtime, using Hotspot JIT (headless)
... 

2.获取甲骨文 JDK 8

1.1 访问甲骨文 JDK 下载页面

1.2 找到一个 Linux x64 版本,在这个例子中,我们将通过wget命令获得jdk-8u66-linux-x64.tar.gz

 $ pwd
/home/mkyong

$ wget --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u66-b17/jdk-8u66-linux-x64.tar.gz 

如果不想用wget(为什么?),只需手动下载文件并上传到您的服务器即可。

3.提取到/opt/jdk/

3.1 将其提取到路径/opt/jdk/jdk1.8.0_66

 $ pwd
/home/mkyong

$ sudo mkdir /opt/jdk/
$ sudo mv ~/jdk-8u66-linux-x64.tar.gz /opt/jdk/
$ sudo cd /opt/jdk/

$ pwd
/opt/jdk/

$ sudo tar -zxf jdk-8u66-linux-x64.tar.gz 
$ ls -ls
total 177056
     4 drwxr-xr-x 3 root root      4096 Oct 27 13:05 .
     4 drwxr-xr-x 3 root root      4096 Oct 27 13:03 ..
     4 drwxr-xr-x 8 uucp  143      4096 Oct  7 00:40 jdk1.8.0_66
177044 -rw-r--r-- 1 root root 181287376 Oct  8 15:56 jdk-8u66-linux-x64.tar.gz 

Note
Alternatively, try this one line extraction command.

 $ sudo tar x -C /opt/jdk -f jdk-8u66-linux-x64.tar.gz 

4.安装 JDK

4.1 将/opt/jdk/jdk1.8.0_66作为/usr/bin/java/usr/bin/javac的新 JDK 替代品

 $ sudo update-alternatives --install /usr/bin/java java /opt/jdk/jdk1.8.0_66/bin/java 100
$ sudo update-alternatives --install /usr/bin/javac javac /opt/jdk/jdk1.8.0_66/bin/javac 100 

4.2 更新javajavac的默认 JDK

 $ update-alternatives --config java
There are 2 choices for the alternative java (providing /usr/bin/java).

  Selection    Path                                            Priority   Status
------------------------------------------------------------
  0            /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java   1051      auto mode
* 1            /opt/jdk/jdk1.8.0_66/bin/java                    100       manual mode
  2            /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java   1051      manual mode

Press enter to keep the current choice[*], or type selection number: 1
update-alternatives: using /opt/jdk/jdk1.8.0_66/bin/java to provide /usr/bin/java (java) in manual mode 
 $ update-alternatives --config javac
There are 2 choices for the alternative javac (providing /usr/bin/javac).

  Selection    Path                                         Priority   Status
------------------------------------------------------------
  0            /usr/lib/jvm/java-7-openjdk-amd64/bin/javac   1051      auto mode
* 1            /opt/jdk/jdk1.8.0_66/bin/javac                100       manual mode
  2            /usr/lib/jvm/java-7-openjdk-amd64/bin/javac   1051      manual mode

Press enter to keep the current choice[*], or type selection number: 1
update-alternatives: using /opt/jdk/jdk1.8.0_66/bin/javac to provide /usr/bin/javac (javac) in manual mode 

5.确认

再次检查 Java 版本。

 $ java -version
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)
root@hydra:/opt/jdk# 

$ javac -version
javac 1.8.0_66 

完成了。享受你的 Lambda!

6.群众演员…怎么升级?

假设新的jdk1.8.0_99发布了,我们想升级它。

6.1 下载 JDK tar 文件并解压到/opt/jdk/jdk1.8.0_99

6.2 不言自明。

 # 6.2.1 Remove the existing alternatives - jdk1.8.0_66
$ sudo update-alternatives --remove java /opt/jdk/jdk1.8.0_66/bin/java
$ sudo update-alternatives --remove javac /opt/jdk/jdk1.8.0_66/bin/javac

# 6.2.2 Install new JDK alternatives - jdk1.8.0_99
$ sudo update-alternatives --install /usr/bin/java java /opt/jdk/jdk1.8.0_99/bin/java 100
$ sudo update-alternatives --install /usr/bin/javac javac /opt/jdk/jdk1.8.0_99/bin/javac 100

# 6.2.3 Update default JDK again, select /opt/jdk/jdk1.8.0_99
$ update-alternatives --config java 
$ update-alternatives --config javac

# 6.2.4 Remove the old JDK folders
$ sudo rm -rf /opt/jdk/jdk1.8.0_66/ 

升级到即将发布的甲骨文 JDK 9 怎么样?你知道该怎么做🙂

参考

  1. 使用 Debian 替代系统
  2. 如何在 Debian 或 Ubuntu VPS 上手动安装 Oracle Java
  3. Debian:改变默认的 Java 版本
  4. 甲骨文 JDK 下载页面

Tags : debian install-java java8 mint ubuntu

如何在 Eclipse 中安装 Spring IDE

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/how-to-install-spring-ide-in-eclipse/

Spring IDE 是一个非常有用的图形用户界面工具,增加了对 Spring 框架的支持。在本教程中,我们将向您展示在 Eclipse 中安装 Spring IDE 的两种方法。

本教程中使用的版本:

  1. Spring IDE 2.9
  2. Eclipse 3.7

Spring IDE or SpringSource Tool Suite (STS)?
Refer to this Spring IDE vs STS pdf file for feature comparison. Personally, I go for Spring IDE for one reason – just can’t let go my existing Eclipse, too many plugins installed.

1.安装新软件

经典方式,Eclipse IDE,点击帮助->-安装新软件 …。键入“【http://springide.org/updatesite】”访问 Spring IDE 更新站点。

选择您想要安装的所有 Spring IDE 特性。

spring ide install new software

完成后需要很长时间来安装和重启 Eclipse。

2.Eclipse 市场

这是更好的方法,因为你不需要记住很长的 Spring ide 更新 URL。在 Eclipse IDE 中,点击“帮助”->”Eclipse market place,输入“ Spring IDE ,按照向导完成安装。

spring ide eclipse marketplace

同样,安装和重启 Eclipse 需要很长时间。

参考

  1. http://www.springsource.com/developer/sts
  2. http://marketplace.eclipse.org/content/spring-ide
  3. http://download . springsource . com/release/STS/doc/STS-feature _ comparison . pdf

eclipse spring spring ide

如何在 Quartz 调度程序中列出所有作业

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-list-all-jobs-in-the-quartz-scheduler/

下面是两个代码片段,向您展示如何列出所有 Quartz 作业。Quartz 2 APIs 变化很大,所以语法和 Quartz 1.x 不一样。

1.石英 2.1.5 示例

 Scheduler scheduler = new StdSchedulerFactory().getScheduler();

   for (String groupName : scheduler.getJobGroupNames()) {

     for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {

	  String jobName = jobKey.getName();
	  String jobGroup = jobKey.getGroup();

	  //get job's trigger
	  List<Trigger> triggers = (List<Trigger>) scheduler.getTriggersOfJob(jobKey);
	  Date nextFireTime = triggers.get(0).getNextFireTime(); 

		System.out.println("[jobName] : " + jobName + " [groupName] : "
			+ jobGroup + " - " + nextFireTime);

	  }

    } 

2.石英 1.8.6 示例

 Scheduler scheduler = new StdSchedulerFactory().getScheduler();

    //loop all group
    for (String groupName : scheduler.getJobGroupNames()) {

	//loop all jobs by groupname
	for (String jobName : scheduler.getJobNames(groupName)) {

          //get job's trigger
	  Trigger[] triggers = scheduler.getTriggersOfJob(jobName,groupName);
	  Date nextFireTime = triggers[0].getNextFireTime();

	  System.out.println("[jobName] : " + jobName + " [groupName] : "
			+ groupName + " - " + nextFireTime);

	}

    } 

Note
You may also interest at this example – list all jobs and display on JSF page. ## 参考

  1. 石英列表工作食谱

quartz scheduler

如何从 Google 代码加载 Ajax 库?

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jquery/how-to-load-ajax-libraries-from-google-code/

谷歌代码托管了很多 Ajax 库,可以从任何服务器或网站免费下载。这里是迄今为止提供的 Ajax 库列表。

  1. jQuery
  2. jQuery UI
  3. 原型
  4. script.aculo.us
  5. MooTools
  6. 柔道训练学校
  7. 雅虎!用户界面库(YUI)

为什么需要从 Google 代码中加载 Ajax 库?

有时候很多人会问为什么要从谷歌代码中加载 Ajax 库?基本上,有两个明显的好处:

  1. 节省带宽——谷歌服务器比你的服务器快,从谷歌代码库加载非常快。
  2. 缓存——如果用户访问了一些使用谷歌代码的网站,谷歌 Ajax 库很有可能被缓存。这将增加您的网站响应时间。

从 Google 代码加载 JQuery 库的例子。

 <script src="http://www.google.com/jsapi"></script>  
<script type="text/javascript">  

    google.load("jquery", "1.2.6");  

    google.setOnLoadCallback(function() {  
          //your code
    });  

</script> 

或者,你也可以像这样包含一个直接链接

 <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"
type="text/javascript"></script> 

参考

  1. http://code . Google . com/APIs/Ajax libs/documentation/index . html

ajax jquery (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190304032337/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

如何从不同的目录加载 hibernate.cfg.xml

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/how-to-load-hibernate-cfg-xml-from-different-directory/

Hibernate XML 配置文件"hibernate.cfg.xml"总是放在项目类路径的根目录下,在任何包之外。如果将此配置文件放在不同的目录中,可能会遇到以下错误:

 Initial SessionFactory creation failed.org.hibernate.HibernateException: 
/hibernate.cfg.xml not found

Exception in thread "main" java.lang.ExceptionInInitializerError
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:25)
	at com.mkyong.persistence.HibernateUtil.<clinit>(HibernateUtil.java:8)
	at com.mkyong.common.App.main(App.java:11)
Caused by: org.hibernate.HibernateException: /hibernate.cfg.xml not found
	at org.hibernate.util.ConfigHelper.getResourceAsStream(ConfigHelper.java:147)
	at org.hibernate.cfg.Configuration.getConfigurationInputStream(Configuration.java:1405)
	at org.hibernate.cfg.Configuration.configure(Configuration.java:1427)
	at org.hibernate.cfg.Configuration.configure(Configuration.java:1414)
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:13)
	... 2 more 

要让 Hibernate 在其他目录中查找您的"hibernate.cfg.xml"文件,您可以通过将您的"hibernate.cfg.xml"文件路径作为参数传递给 configure() 方法来修改默认 Hibernate 的SessionFactory类:

 SessionFactory sessionFactory = new Configuration()
            .configure("/com/mkyong/persistence/hibernate.cfg.xml")
            .buildSessionFactory();

            return sessionFactory; 

HibernateUtil.java

HibernateUtil.java中的完整示例,从目录“ /com/mkyong/persistence/ ”中加载“hibernate.cfg.xml”。

 import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {

	private static final SessionFactory sessionFactory = buildSessionFactory();

	private static SessionFactory buildSessionFactory() {
		try {
			// load from different directory
			SessionFactory sessionFactory = new Configuration().configure(
					"/com/mkyong/persistence/hibernate.cfg.xml")
					.buildSessionFactory();

			return sessionFactory;

		} catch (Throwable ex) {
			// Make sure you log the exception, as it might be swallowed
			System.err.println("Initial SessionFactory creation failed." + ex);
			throw new ExceptionInInitializerError(ex);
		}
	}

	public static SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public static void shutdown() {
		// Close caches and connection pools
		getSessionFactory().close();
	}

} 

完成了。

hibernate (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190306165539/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

如何用 jQuery 在运行时加载 JavaScript

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jquery/how-to-load-javascript-at-runtime-with-jquery/

为了提高网站性能并减少总的文件大小返回,您可以考虑加载 JavaSript(。js)文件。在 jQuery 中,可以使用 $。getScript 函数在运行时或按需加载 JavaScript 文件。

举个例子,

 $("#load").click(function(){
	$.getScript('helloworld.js', function() {
  		$("#content").html('Javascript is loaded successful!');
	});
}); 

当点击一个 Id 为“load”的按钮时,会动态加载“hello world . js”JavaScript 文件。

你自己试试

在这个例子中,当你点击 load 按钮时,它将在运行时加载“ js-example/helloworld.js ”,其中包含一个“ sayhello() 函数。

 <html>
<head>

<script type="text/javascript" src="jquery-1.4.2.min.js"></script>

</head>
<body>
  <h1>Load Javascript dynamically with jQuery</h1>

<div id="content"></div>
<br/>

<button id="load">Load JavaScript</button>
<button id="sayHello">Say Hello</button>

<script type="text/javascript">

$("#load").click(function(){
  $.getScript('js-example/helloworld.js', function() {
     $("#content").html('
          Javascript is loaded successful! sayHello() function is loaded!
     ');
  });
});

$("#sayHello").click(function(){
  sayHello();
});

</script>
</body>
</html> 

http://web.archive.org/web/20190223075932if_/http://www.mkyong.com/wp-content/uploads/jQuery/jQuery-load-javascript-at-runtime.html

Try Demojavascript jquery (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190223075932/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

Java——将 XML 转换成属性文件

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-load-properties-from-xml-file/

本文展示了如何将 XML 文件转换成属性文件。

目录

用 Java 11 测试。

1。属性–将 XML 文件转换为属性文件

下面的例子使用Properties#loadFromXML()加载一个 XML 文件并将其转换为属性值。

1.1 一个使用properties.dtd的 XML 文件。

server.xml

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
    <comment>Server config file</comment>
    <entry key="http.port">8080</entry>
    <entry key="email.support">donot-spam-me@nospam.com</entry>
    <entry key="http.server">localhost</entry>
    <entry key="http.port">8080</entry>
</properties> 

1.2 我们可以使用Properties#loadFromXML()将 XML 文件加载到属性值中。

ConvertXmlToProperties.java

 package com.mkyong.xml.tips;

import java.io.*;
import java.util.Properties;

public class ConvertXmlToProperties {

    public static void main(String[] args) throws IOException {

        Properties props = new Properties();
        try (InputStream input =
                     new FileInputStream("src/main/resources/server.xml")) {
            // loads from XML into a properties file
            props.loadFromXML(input);
        }

        try (OutputStream output =
                     new FileOutputStream("c:\\test\\server.properties")) {

            props.store(output, "");

        }

    }

} 

1.3 输出—c:\\test\\server.properties

 #
#Sun May 16 16:51:31 SGT 2021
http.port=8080
email.support=donot-spam-me@nospam.com
http.server=localhost 

1.4 为了使Properties#loadFromXML()正常工作,XML 文档必须有以下 DOCTYPE 声明:

 <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> 

因为我们声明了DOCTYPEproperties.dtd,所以 XML 文档也必须遵循下面的properties.dtd格式。

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
    <entry key="key1">value1</entry>
</properties> 

如果 XML 文件未能遵循上面在properties.dtd中定义的格式,JDK 会在加载 XML 文件时抛出一条错误消息。

2。DOM–将 XML 文件转换成属性文件

这个示例使用 DOM 解析器读取 XML 文件,并将值转换成属性文件。

2.1 一个 XML 文件。

staff.xml

 <?xml version="1.0" encoding="utf-8"?>
<company>
    <staff id="1001">
        <name>mkyong</name>
    </staff>
    <staff id="1002">
        <name>yflow</name>
    </staff>
</company> 

2.2 DOM 解析器读取 XML 并将其转换为Properties对象。

ConvertXmlToPropertiesDom.java

 package com.mkyong.xml.tips;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
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.*;
import java.util.Properties;

public class ConvertXmlToPropertiesDom {

    public static void main(String[] args)
            throws IOException, ParserConfigurationException, SAXException {

        Document doc;
        Properties prop = new Properties();

        try (FileInputStream input =
                     new FileInputStream("src/main/resources/staff.xml")) {
            // convert XML file to Document
            doc = parse(input);
        }

        NodeList list = doc.getElementsByTagName("staff");

        for (int temp = 0; temp < list.getLength(); temp++) {

            Node node = list.item(temp);

            if (node.getNodeType() == Node.ELEMENT_NODE) {

                Element element = (Element) node;

                // get staff's id
                String id = element.getAttribute("id");

                // get text
                String name = element.getElementsByTagName("name")
                        .item(0).getTextContent();

                // write value to properties
                // prop does not guarantee on the order
                prop.setProperty("company.staff" + temp + ".id", id);
                prop.setProperty("company.staff" + temp + ".name", name);

            }

        }

        // write to console for testing
        prop.store(System.out, "");

        // write to a properties file
        /*try (FileOutputStream output =
                     new FileOutputStream("c:\\test\\staff.properties")) {
            prop.store(output, "");
        }*/

    }

    // get document
    private static Document parse(InputStream input)
            throws ParserConfigurationException, IOException, SAXException {

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.parse(input);
        return doc;

    }

} 

输出

Terminal

 #
#Sun May 16 17:43:20 SGT 2021
company.staff0.name=mkyong
company.staff0.id=1001
company.staff1.name=yflow
company.staff1.id=1002 

SAX、StAX、JDOM、JAXB 怎么样?
上述 DOM 解析器思想适用于所有其他 XML 解析器,比如 SAX、StAX、JDOM 或 JAXB。我们使用 XML 解析器读取 XML 值,并将它们存储在一个Properties对象中。

3。下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-xml

$ CD src/main/Java/com/mkyong/XML/tips/

4。参考文献

如何在 Java 中循环地图

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-loop-a-map-in-java/

这段代码片段向您展示了如何在 Java 中循环一个Map

 Map<String, String> map = new HashMap<>();
	map.put("1", "Jan");
	map.put("2", "Feb");
	map.put("3", "Mar");

	// classic way, loop a Map
	for (Map.Entry<String, String> entry : map.entrySet()) {
		System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());
	}

	//Java 8 only, forEach and Lambda
	map.forEach((k,v)->System.out.println("Key : " + k + " Value : " + v)); 

输出

 Key : 1 Value :Jan
    Key : 2 Value :Feb
    Key : 3 Value :Mar

    Key : 1 Value :Jan
    Key : 2 Value :Feb
    Key : 3 Value :Mar 

1.例子

不同的循环方式Map

LoopMap.java

 package com.mkyong;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class LoopMap {

    public static void main(String[] args) {

        // initial a Map
        Map<String, String> map = new HashMap<>();
        map.put("1", "Jan");
        map.put("2", "Feb");
        map.put("3", "Mar");
        map.put("4", "Apr");
        map.put("5", "May");
        map.put("6", "Jun");

        // Standard classic way, recommend!
        System.out.println("\nExample 1...");
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());
        }

        // Java 8, forEach and Lambda. recommend!
        System.out.println("\nExample 2...");
        map.forEach((k, v) -> System.out.println("Key : " + k + " Value : " + v));

        // Map -> Set -> Iterator -> Map.Entry -> troublesome, don't use, just for fun
        System.out.println("\nExample 3...");
        Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, String> entry = iterator.next();
            System.out.println("Key : " + entry.getKey() + " Value :" + entry.getValue());
        }

        // weired, but works anyway, don't use, just for fun
        System.out.println("\nExample 4...");
        for (Object key : map.keySet()) {
            System.out.println("Key : " + key.toString() + " Value : " + map.get(key));
        }

    }

} 

输出

 Example 1...
Key : 1 Value : Jan
Key : 2 Value : Feb
Key : 3 Value : Mar
Key : 4 Value : Apr
Key : 5 Value : May
Key : 6 Value : Jun

Example 2...
Key : 1 Value : Jan
Key : 2 Value : Feb
Key : 3 Value : Mar
Key : 4 Value : Apr
Key : 5 Value : May
Key : 6 Value : Jun

Example 3...
Key : 1 Value :Jan
Key : 2 Value :Feb
Key : 3 Value :Mar
Key : 4 Value :Apr
Key : 5 Value :May
Key : 6 Value :Jun

Example 4...
Key : 1 Value : Jan
Key : 2 Value : Feb
Key : 3 Value : Mar
Key : 4 Value : Apr
Key : 5 Value : May
Key : 6 Value : Jun 

2.地图过滤

在 Java 8 中,你可以将一个Map转换成一个Stream并像这样过滤它:

 map.entrySet().stream()
        .filter(x -> "Jan".equals(x.getValue()))
        .forEach( x -> System.out.println("Key : " + x.getKey() + " Value : " + x.getValue())); 

输出

 Key : 1 Value : Jan 

Note
More examples, please read this Java 8 – Filter a Map examples

参考

  1. Java . util . iterator JavaDoc
  2. java.util.Map JavaDoc
  3. Java 8 forEach 示例
  4. 在 Java 8 中迭代集合

Tags : java8 loop loop map map map filter

如何用安卓打电话

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/how-to-make-a-phone-call-in-android/

在本教程中,我们将向您展示如何在 Android 中拨打电话,并通过PhoneStateListener监控电话通话状态。

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1 个 Android 布局文件

Simpel 布局文件,显示一个按钮。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/buttonCall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="call 0377778888" />

</LinearLayout> 

2.活动

使用下面的代码片段在 Android 中打电话。

 Intent callIntent = new Intent(Intent.ACTION_CALL);
	callIntent.setData(Uri.parse("tel:0377778888"));
	startActivity(callIntent); 

档:MainActivity.java——当按钮为通话时,拨打 0377778888。

 package com.mkyong.android;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {

	private Button button;

	public void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		button = (Button) findViewById(R.id.buttonCall);

		// add button listener
		button.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {

				Intent callIntent = new Intent(Intent.ACTION_CALL);
				callIntent.setData(Uri.parse("tel:0377778888"));
				startActivity(callIntent);

			}

		});

	}

} 

3 Android 清单

要打电话,Android 需要 CALL_PHONE 权限。

 <uses-permission android:name="android.permission.CALL_PHONE" /> 

文件:AndroidManifest.xml

 <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mkyong.android"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="10" />

	<uses-permission android:name="android.permission.CALL_PHONE" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >

        <activity
            android:label="@string/app_name"
            android:name=".MainActivity" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest> 

4.PhoneStateListener 示例

好了,现在我们更新上面的活动,来监视电话呼叫状态,当一个电话呼叫结束时,回到原来的活动(实际上,它只是重新开始活动)。看评论,应该不言自明。

Note
Run it and refer to the logcat console to understand how PhoneStateListener works.

文件:MainActivity.java

 package com.mkyong.android;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {

	final Context context = this;
	private Button button;

	public void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		button = (Button) findViewById(R.id.buttonCall);

		// add PhoneStateListener
		PhoneCallListener phoneListener = new PhoneCallListener();
		TelephonyManager telephonyManager = (TelephonyManager) this
			.getSystemService(Context.TELEPHONY_SERVICE);
		telephonyManager.listen(phoneListener,PhoneStateListener.LISTEN_CALL_STATE);

		// add button listener
		button.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {

				Intent callIntent = new Intent(Intent.ACTION_CALL);
				callIntent.setData(Uri.parse("tel:0377778888"));
				startActivity(callIntent);

			}

		});

	}

	//monitor phone call activities
	private class PhoneCallListener extends PhoneStateListener {

		private boolean isPhoneCalling = false;

		String LOG_TAG = "LOGGING 123";

		@Override
		public void onCallStateChanged(int state, String incomingNumber) {

			if (TelephonyManager.CALL_STATE_RINGING == state) {
				// phone ringing
				Log.i(LOG_TAG, "RINGING, number: " + incomingNumber);
			}

			if (TelephonyManager.CALL_STATE_OFFHOOK == state) {
				// active
				Log.i(LOG_TAG, "OFFHOOK");

				isPhoneCalling = true;
			}

			if (TelephonyManager.CALL_STATE_IDLE == state) {
				// run when class initial and phone call ended, 
				// need detect flag from CALL_STATE_OFFHOOK
				Log.i(LOG_TAG, "IDLE");

				if (isPhoneCalling) {

					Log.i(LOG_TAG, "restart app");

					// restart app
					Intent i = getBaseContext().getPackageManager()
						.getLaunchIntentForPackage(
							getBaseContext().getPackageName());
					i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
					startActivity(i);

					isPhoneCalling = false;
				}

			}
		}
	}

} 

再次更新 Android 清单文件,PhoneStateListener需要 READ_PHONE_STATE 权限。

 <uses-permission android:name="android.permission.READ_PHONE_STATE" /> 

文件:AndroidManifest.xml

 <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mkyong.android"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="10" />

    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >

        <activity
            android:label="@string/app_name"
            android:name=".MainActivity" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest> 

5.演示

活动开始后,只显示一个按钮。

android phone call example

点击按钮后,拨打电话 0377778888。

android phone call example

当电话挂断或结束时,重新开始主要活动。

android phone call example

下载源代码

Download it – Android-Make-Phone-Call-Example.zip (16 KB)

参考

  1. Android PhoneStateListener Javadoc
  2. 安卓手机管理器 Javadoc
  3. Android Intent Javadoc

android phone call

如何让 Eclipse IDE 支持 JSF 2.0

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/how-to-make-eclipse-ide-supports-jsf-2-0/

在 Eclipse Ganymede(3.4 版)或 Galileo(3.5 版)中,它只支持 JSF 1.2 版。对于 JSF 2.0 ,把你的 Eclipse 升级到Helios(3.6)版本以后,它已经完全支持 Java EE 6 支持,包括 JSF 2.0。

这里有一个快速指南,向您展示如何在 Eclipse IDE 中启用 JSF 2.0 的特性,比如代码辅助和可视化 JSF 组件编辑器。

使用的工具

  1. Eclipse 3.6
  2. JSF 2.0.x

1.Eclipse 项目方面

为了支持 JSF 2.0,你需要配置 Eclipse 项目来支持 Web 工具平台(WTP)

启用网络工具平台的步骤(WTP):

  1. 右击项目,选择“属性”—>“项目刻面”。
  2. 勾选动态网页模块,选择版本 2.5。
  3. 勾选 Java ,选择版本 1.6。
  4. 勾选“ JavaServer Faces ,选择版本 2.0。【T2eclipse-jsf-support
  5. 点击下面的“进一步配置… ”链接进行 JSF 配置。
  6. 创建一个用户库,包括 JSF 2.0 API 和实现库, jsf-api-xxx.jarjsf-impl-xxx.jar
    P.S 你可以在 JSF 官方网站获得 JSF 坛子eclipse-jsf-support2012 年 8 月 8 日更新
    对于 JSF 2.1.11,只需要一个 jar 文件 javax.faces-2.1.11。
  7. 完成了。

2.演示

现在,Eclipse IDE 支持 JSF 2.0 的功能。试试看,在.xhtml文件中,点击“ Ctrl +空格键,会自动提示所有可用的 JSF 2.0 标签(代码辅助)。

此外,它还在网页编辑器中添加了 JSF 2.0 可视化组件,见下图:

eclipse-jsf-support

如何在 Java 中修改 XML 文件—(DOM 解析器)

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

本教程展示了如何使用 Java 内置的 DOM 解析器来修改 XML 文件。

目录

用 Java 11 测试。

注意
请阅读 DOM parse XMLDOM write XML

1。XML 文件,

前后

原始 XML 文件。

staff-simple.xml

 <?xml version="1.0" encoding="utf-8"?>
<company>
    <staff id="1001">
        <name>mkyong</name>
        <role>support</role>
    </staff>
    <staff id="1002">
        <name>yflow</name>
        <role>admin</role>
    </staff>
</company> 

稍后我们将使用 DOM 解析器来修改以下 XML 数据。

对于员工 id 1001

  • 移除 XML 元素name
  • 对于 XML 元素role,将值更新为“founder”。

对于员工 id 1002

  • 将 XML 属性更新为2222
  • 添加一个新的 XML 元素salary,包含属性和值。
  • 添加新的 XML 注释。
  • 重命名一个 XML 元素,从namen(删除和添加)。

下面是最终修改后的 XML 文件。

 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<company>
    <staff id="1001">
        <role>founder</role>
    </staff>
    <staff id="2222">
        <role>admin</role>
        <salary currency="USD">1000</salary>
        <!--from name to n-->
        <n>yflow</n>
    </staff>
</company> 

2。Dom 解析器修改 XML 文件

下面是 DOM 解析器获取原始 XML 文件staff-simple.xml,修改 XML 并生成修改后的 XML 文件staff-modified.xml的例子。

ModifyXmlDomParser.java

 package com.mkyong.xml.dom;

import org.w3c.dom.*;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.*;

public class ModifyXmlDomParser {

    private static final String FILENAME = "src/main/resources/staff-simple.xml";
    // xslt for pretty print only, no special task
    private static final String FORMAT_XSLT = "src/main/resources/xslt/staff-format.xslt";

    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);

            NodeList listOfStaff = doc.getElementsByTagName("staff");
            //System.out.println(listOfStaff.getLength()); // 2

            for (int i = 0; i < listOfStaff.getLength(); i++) {
                // get first staff
                Node staff = listOfStaff.item(i);
                if (staff.getNodeType() == Node.ELEMENT_NODE) {
                    String id = staff.getAttributes().getNamedItem("id").getTextContent();
                    if ("1001".equals(id.trim())) {

                        NodeList childNodes = staff.getChildNodes();

                        for (int j = 0; j < childNodes.getLength(); j++) {
                            Node item = childNodes.item(j);
                            if (item.getNodeType() == Node.ELEMENT_NODE) {

                                if ("role".equalsIgnoreCase(item.getNodeName())) {
                                    // update xml element `role` text
                                    item.setTextContent("founder");
                                }
                                if ("name".equalsIgnoreCase(item.getNodeName())) {
                                    // remove xml element `name`
                                    staff.removeChild(item);
                                }
                            }

                        }

                        // add a new xml element, address
                        Element address = doc.createElement("address");
                        // add a new xml CDATA
                        CDATASection cdataSection =
                                doc.createCDATASection("HTML tag <code>testing</code>");

                        address.appendChild(cdataSection);

                        staff.appendChild(address);

                    }

                    if ("1002".equals(id.trim())) {

                        // update xml attribute, from 1002 to 2222
                        staff.getAttributes().getNamedItem("id").setTextContent("2222");

                        // add a new xml element, salary
                        Element salary = doc.createElement("salary");
                        salary.setAttribute("currency", "USD");
                        salary.appendChild(doc.createTextNode("1000"));
                        staff.appendChild(salary);

                        // rename a xml element from `name` to `n`
                        // sorry, no API for this, we need to remove and create
                        NodeList childNodes = staff.getChildNodes();

                        for (int j = 0; j < childNodes.getLength(); j++) {
                            Node item = childNodes.item(j);
                            if (item.getNodeType() == Node.ELEMENT_NODE) {

                                if ("name".equalsIgnoreCase(item.getNodeName())) {

                                    // Get the text of element `name`
                                    String name = item.getTextContent();

                                    // remove xml element `name`
                                    staff.removeChild(item);

                                    // add a new xml element, n
                                    Element n = doc.createElement("n");
                                    n.appendChild(doc.createTextNode(name));

                                    // add a new comment
                                    Comment comment = doc.createComment("from name to n");
                                    staff.appendChild(comment);

                                    staff.appendChild(n);

                                }
                            }

                        }

                    }

                }

            }

            // output to console
            // writeXml(doc, System.out);

            try (FileOutputStream output =
                         new FileOutputStream("c:\\test\\staff-modified.xml")) {
                writeXml(doc, output);
            }

        } catch (ParserConfigurationException | SAXException
                | IOException | TransformerException e) {
            e.printStackTrace();
        }

    }

    // write doc to output stream
    private static void writeXml(Document doc,
                                 OutputStream output)
            throws TransformerException, UnsupportedEncodingException {

        TransformerFactory transformerFactory = TransformerFactory.newInstance();

        // The default add many empty new line, not sure why?
        // https://mkyong.com/java/pretty-print-xml-with-java-dom-and-xslt/
        // Transformer transformer = transformerFactory.newTransformer();

        // add a xslt to remove the extra newlines
        Transformer transformer = transformerFactory.newTransformer(
                new StreamSource(new File(FORMAT_XSLT)));

        // pretty print
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty(OutputKeys.STANDALONE, "no");

        DOMSource source = new DOMSource(doc);
        StreamResult result = new StreamResult(output);

        transformer.transform(source, result);

    }

} 

输出–修改后的 XML 文件。

c:\test\staff-modified.xml

 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<company>
    <staff id="1001">
        <role>founder</role>
        <address>
            <![CDATA[HTML tag <code>testing</code>]]>
        </address>
    </staff>
    <staff id="2222">
        <role>admin</role>
        <salary currency="USD">1000</salary>
        <!--from name to n-->
        <n>yflow</n>
    </staff>
</company> 

3。下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-xml

$ CD src/main/Java/com/mkyong/XML/DOM/

4。参考文献

如何在 Java 中修改 XML 文件—(JDOM)

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

本教程展示了如何使用 JDOM 来修改 XML 文件。

目录

用 JDOM 2.0.6 测试的 PS

注意
我们需要了解 JDOM 如何解析 XML编写 XML ,以便修改 XML 文档。

1。下载 JDOM 2.x

Maven for JDOM。

pom.xml

 <dependency>
      <groupId>org.jdom</groupId>
      <artifactId>jdom2</artifactId>
      <version>2.0.6</version>
  </dependency> 

2。XML 文件,

前后

2.1 原始 XML 文件。

c:\test\staff.xml

 <?xml version="1.0" encoding="utf-8"?>
<company>
    <staff id="1001">
        <name>mkyong</name>
        <role>support</role>
        <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.2 见下图 JDOM 示例修改上述 XML,添加、删除和更新元素、属性、注释、CDATA 等。

对于员工,id 是 1001

  1. 移除 XML 元素role
  2. 更新 XML 元素salary,将属性更新为 MYR

对于员工,id 是 1002

  1. 移除 xml 元素name
  2. 添加新的 xml 元素address和 CDATA 内容
  3. 将 xml 元素salary更新为 2000
  4. 移除 xml 元素 CDATA

另外,添加一个新的 XML 子节点staff,并删除所有 XML 注释。

下面是修改后的 XML 输出。

c:\test\staff.xml

 <?xml version="1.0" encoding="UTF-8"?>
<company>
  <staff id="1001">
    <name>mkyong</name>
    <salary currency="MYR">5000</salary>
    <bio><![CDATA[HTML tag <code>testing</code>]]></bio>
  </staff>
  <staff id="1002">
    <role>admin</role>
    <salary currency="EUR">2000</salary>
    <bio>a &amp; b &amp; c</bio>
    <address><![CDATA[123 & abc]]></address>
  </staff>
  <staff id="1003" />
</company> 

3。修改 XML 文件

下面的例子使用 JDOM 解析 XML 文件上面的,修改内容并将其写入文件。

阅读代码注释,这是不言自明的。

ModifyXmlJDom.java

 package com.mkyong.xml.jdom;

import org.jdom2.CDATA;
import org.jdom2.Content;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

public class ModifyXmlJDom {

    private static final String FILENAME = "src/main/resources/staff.xml";

    public static void main(String[] args) throws JDOMException, IOException {

        SAXBuilder sax = new SAXBuilder();
        Document doc = sax.build(new File(FILENAME));

        Element rootNode = doc.getRootElement();

        List<Element> listChildrenNode = rootNode.getChildren("staff");

        // staff = 2
        System.out.println("No of child nodes: " + listChildrenNode.size());

        // loop the elements
        for (Element staff : listChildrenNode) {

            String id = staff.getAttribute("id").getValue();

            // if staff id is 1001
            if ("1001".equals(id.trim())) {

                // remove element role
                staff.removeChild("role");

                // update xml element `salary`, update attribute to MYR
                staff.getChild("salary").setAttribute("currency", "MYR");

            }

            // if staff id is 1002
            if ("1002".equals(id.trim())) {

                // remove xml element `name`
                staff.removeChild("name");

                // add a new xml element `address` and CDATA content
                staff.addContent(new Element("address")
                        .addContent(new CDATA("123 & abc")));

                // update xml element `salary` to 2000
                staff.getChild("salary").setText("2000");

                // remove the xml element CDATA
                staff.getChild("bio").setText("a & b & c"); // now the & will escape automatically
            }

            // Java 8 to remove all XML comments
            staff.getContent().removeIf(
                    content -> content.getCType() == Content.CType.Comment);

            // remove the XML comments via iterator
            /*ListIterator<Content> iter = staff.getContent().listIterator();
            while (iter.hasNext()) {
                Content content = iter.next();
                if (content.getCType() == Content.CType.Comment) {
                    iter.remove();
                }
            }*/

        }

        // add a new XML child node, staff id 1003
        rootNode.addContent(new Element("staff").setAttribute("id", "1003"));

        // print to console for testing
        XMLOutputter xmlOutput = new XMLOutputter();
        xmlOutput.setFormat(Format.getPrettyFormat());

        // write to console
        // xmlOutput.output(doc, System.out);

        // write to a file
        try (FileOutputStream output =
                     new FileOutputStream("c:\\test\\staff-update.xml")) {
            xmlOutput.output(doc, output);
        }

    }

} 

输出

c:\test\staff-update.xml

 <?xml version="1.0" encoding="UTF-8"?>
<company>
  <staff id="1001">
    <name>mkyong</name>
    <salary currency="MYR">5000</salary>
    <bio><![CDATA[HTML tag <code>testing</code>]]></bio>
  </staff>
  <staff id="1002">
    <role>admin</role>
    <salary currency="EUR">2000</salary>
    <bio>a &amp; b &amp; c</bio>
    <address><![CDATA[123 & abc]]></address>
  </staff>
  <staff id="1003" />
</company> 

4。查找并删除 XML 元素

如果一个 XML 元素name等于mkyong,删除它的数据,以及整个staff元素。

ModifyXmlJDom4.java

 package com.mkyong.xml.jdom;

import org.jdom2.CDATA;
import org.jdom2.Content;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

public class ModifyXmlJDom4 {

  private static final String FILENAME = "src/main/resources/staff.xml";

  public static void main(String[] args) throws JDOMException, IOException {

      SAXBuilder sax = new SAXBuilder();

      Document doc = sax.build(new File(FILENAME));

      Element rootNode = doc.getRootElement();

      List<Element> listChildrenNode = rootNode.getChildren("staff");

      // loop the elements
      for (Element staff : listChildrenNode) {

          // if name = mkyong, remove the staff node
          if ("mkyong".equals(staff.getChildText("name"))) {
              rootNode.removeContent(staff);
          }

      }

      // print to console for testing
      XMLOutputter xmlOutput = new XMLOutputter();
      xmlOutput.setFormat(Format.getPrettyFormat());

      // write to console
      xmlOutput.output(doc, System.out);

  }

} 

输出

Terminal

 <?xml version="1.0" encoding="UTF-8"?>
<company>
  <staff id="1002">
    <name>yflow</name>
    <role>admin</role>
    <salary currency="EUR">8000</salary>
    <bio><![CDATA[a & b]]></bio>
  </staff>
</company> 


更多 JDOM2 示例——JDOM 2 入门

5。下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-xml

$ CD src/main/Java/com/mkyong/XML/JDOM/

6。参考文献

如何在 Java 中将文件移动到另一个目录

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

本文展示了如何将文件移动到同一个文件驱动器或远程服务器中的另一个目录。

  • Files.move–在本地系统中移动文件。
  • JSch–移动文件以移除服务器(SFTP)

1.将文件移动到另一个目录

这个 Java 示例使用 NIO Files.move将文件从移动到同一个本地驱动器中的另一个目录。

FileMove.java

 package com.mkyong.io.file;

import java.io.IOException;
import java.nio.file.*;

public class FileMove {

    public static void main(String[] args) {

        String fromFile = "/home/mkyong/data/db.debug.conf";
        String toFile = "/home/mkyong/data/deploy/db.conf";

        Path source = Paths.get(fromFile);
        Path target = Paths.get(toFile);

        try {

            // rename or move a file to other path
            // if target exists, throws FileAlreadyExistsException
            Files.move(source, target);

            // if target exists, replace it.
            // Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);

            // multiple CopyOption
            /*CopyOption[] options = { StandardCopyOption.REPLACE_EXISTING,
                                StandardCopyOption.COPY_ATTRIBUTES,
                                LinkOption.NOFOLLOW_LINKS };

            Files.move(source, target, options);*/

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
} 

更多 Java 文件移动的例子。

2.将文件移动到远程服务器目录

这个 Java 示例使用 JSch 库将文件从本地系统移动到远程服务器的另一个目录,使用 SFTP

P.S .假设远程服务器启用了使用密码的 SSH 登录(默认端口 22)。

pom.xml

 <dependency>
      <groupId>com.jcraft</groupId>
      <artifactId>jsch</artifactId>
      <version>0.1.55</version>
  </dependency> 

SFTPFileTransfer.java

 package com.mkyong.io.howto;

import com.jcraft.jsch.*;

public class SFTPFileTransfer {

    private static final String REMOTE_HOST = "1.2.3.4";
    private static final String USERNAME = "";
    private static final String PASSWORD = "";
    private static final int REMOTE_PORT = 22;
    private static final int SESSION_TIMEOUT = 10000;
    private static final int CHANNEL_TIMEOUT = 5000;

    public static void main(String[] args) {

        // local
        String localFile = "/home/mkyong/hello.sh";

        // remote server
        String remoteFile = "/home/mkyong/test.sh";

        Session jschSession = null;

        try {

            JSch jsch = new JSch();
            jsch.setKnownHosts("/home/mkyong/.ssh/known_hosts");
            jschSession = jsch.getSession(USERNAME, REMOTE_HOST, REMOTE_PORT);

            // authenticate using private key
            // jsch.addIdentity("/home/mkyong/.ssh/id_rsa");

            // authenticate using password
            jschSession.setPassword(PASSWORD);

            // 10 seconds session timeout
            jschSession.connect(SESSION_TIMEOUT);

            Channel sftp = jschSession.openChannel("sftp");

            // 5 seconds timeout
            sftp.connect(CHANNEL_TIMEOUT);

            ChannelSftp channelSftp = (ChannelSftp) sftp;

            // transfer file from local to remote server
            channelSftp.put(localFile, remoteFile);

            // download file from remote server to local
            // channelSftp.get(remoteFile, localFile);

            channelSftp.exit();

        } catch (JSchException | SftpException e) {

            e.printStackTrace();

        } finally {
            if (jschSession != null) {
                jschSession.disconnect();
            }
        }

    }

} 

请访问此文件传输使用 Java 中的 SFTP(JSch)

注意NIOFiles.move不能将文件从本地系统移动到远程服务器目录。

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-io

参考

如何在 Android 的网络浏览器中打开一个网址

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/how-to-open-an-url-in-androids-web-browser/

这里有一个代码片段,展示了如何使用“android.content.Intent”在 Android 的网络浏览器中打开一个指定的 URL。

 button.setOnClickListener(new OnClickListener() {

		@Override
		public void onClick(View arg0) {

			Intent intent = new Intent(Intent.ACTION_VIEW, 
			     Uri.parse("http://www.mkyong.com"));
			startActivity(intent);

		}

	}); 

Note
For full example, please refer to this – Android button example.

参考

  1. 安卓按钮 JavaDoc
  2. 安卓意向。ACTION_VIEW JavaDoc

android browser url (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190215001302/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

gson–如何解析 JSON

原文:http://web.archive.org/web/20230101150211/https://www.mkyong.com/java/how-to-parse-json-with-gson/

Gson 提供简单的toJson()fromJson()方法,将 Java 对象转换成 JSON 对象或从 JSON 对象转换过来。

toJson()–JSON 的 Java 对象

 Gson gson = new Gson();

	// 1\. Java object to JSON file
	gson.toJson(obj, new FileWriter("C:\\fileName.json"));

	// 2\. Java object to JSON string
	String json = gson.toJson(obj); 

fromJson()–JSON 到 Java 对象

 Gson gson = new Gson();

	// 1\. JSON file to Java object
	Object object = gson.fromJson(new FileReader("C:\\fileName.json"), Object.class);

	// 2\. JSON string to Java object
	String json = "{'name' : 'mkyong'}";
	Object object = gson.fromJson(json, Staff.class); 

1.下载 Gson

pom.xml

 <dependency>
		<groupId>com.google.code.gson</groupId>
		<artifactId>gson</artifactId>
		<version>2.8.5</version>
	</dependency> 

2.Java 对象

以便以后测试。

Staff.java

 package com.mkyong;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class Staff {

    private String name;
    private int age;
    private String[] position;              // array
    private List<String> skills;            // list
    private Map<String, BigDecimal> salary; // map

    //getters and setters
} 

3.JSON 的 Java 对象

3.1 在 Gson 中,我们可以使用gson.toJson()将 Java 对象转换成 JSON。

GsonExample1.java

 package com.mkyong;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class GsonExample1 {

    public static void main(String[] args) {

        // pretty print
        Gson gson = new GsonBuilder().setPrettyPrinting().create();

        Staff staff = createStaffObject();

        // Java objects to String
        String json = gson.toJson(staff);

        //System.out.println(json);

        // Java objects to File
        try (FileWriter writer = new FileWriter("c:\\test\\staff.json")) {
            gson.toJson(staff, writer);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private static Staff createStaffObject() {

        Staff staff = new Staff();

        staff.setName("mkyong");
        staff.setAge(35);
        staff.setPosition(new String[]{"Founder", "CTO", "Writer"});
        Map<String, BigDecimal> salary = new HashMap() {{
            put("2010", new BigDecimal(10000));
            put("2012", new BigDecimal(12000));
            put("2018", new BigDecimal(14000));
        }};
        staff.setSalary(salary);
        staff.setSkills(Arrays.asList("java", "python", "node", "kotlin"));

        return staff;

    }

} 

输出

c:\test\staff.json

 {
  "name": "mkyong",
  "age": 35,
  "position": [
    "Founder",
    "CTO",
    "Writer"
  ],
  "skills": [
    "java",
    "python",
    "node",
    "kotlin"
  ],
  "salary": {
    "2018": 14000,
    "2012": 12000,
    "2010": 10000
  }
} 

4.JSON 到 Java 对象

4.1 在 Gson 中,我们可以使用gson.fromJson将 JSON 转换回 Java 对象。

GsonExample2.java

 package com.mkyong;

import com.google.gson.Gson;

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class GsonExample2 {

    public static void main(String[] args) {

        Gson gson = new Gson();

        try (Reader reader = new FileReader("c:\\test\\staff.json")) {

            // Convert JSON File to Java Object
            Staff staff = gson.fromJson(reader, Staff.class);

			// print staff 
            System.out.println(staff);

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

} 

输出

 Staff{name='mkyong', age=35, position=[Founder, CTO, Writer], skills=[java, python, node, kotlin], salary={2018=14000, 2012=12000, 2010=10000}} 

5.漂亮的打印 JSON

5.1 默认的 JSON 输出是压缩模式。

GsonExample3.java

 package com.mkyong;

import com.google.gson.Gson;

public class GsonExample3 {

    public static void main(String[] args) {

        // compact print
        Gson gson = new Gson();

        String[] lang = {"Java", "Node", "Kotlin", "JavaScript"};
        String json = gson.toJson(lang);

        System.out.println(json);

    }

} 

输出

 ["Java","Node","Kotlin","JavaScript"] 

5.2 启用漂亮打印。

GsonExample4.java

 package com.mkyong;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class GsonExample4 {

    public static void main(String[] args) {

        // pretty print
        Gson gson = new GsonBuilder().setPrettyPrinting().create();

        String[] lang = {"Java", "Node", "Kotlin", "JavaScript"};
        String json = gson.toJson(lang);

        System.out.println(json);

    }

} 

输出

 [
  "Java",
  "Node",
  "Kotlin",
  "JavaScript"
] 

6.排除字段

在 Gson 中,有很多方法可以排除某些字段。

6.1 默认情况下,transientstatic字段将被排除。我们可以通过excludeFieldsWithModifiers覆盖默认设置

如果我们只想排除静态字段。

 import java.lang.reflect.Modifier;

	Gson gson = new GsonBuilder()
			.excludeFieldsWithModifiers(Modifier.STATIC)
			.create(); 

如果我们想排除瞬态和静态字段,默认。

 import java.lang.reflect.Modifier;

	Gson gson = new GsonBuilder()
			.excludeFieldsWithModifiers(Modifier.STATIC, Modifier.TRANSIENT)
			.create(); 

在这种配置中,将包括静态和瞬态场。

 Gson gson = new GsonBuilder()
			.excludeFieldsWithModifiers()
			.create(); 

6.2 通过@Expose排除字段

@Expose定义了从 JSON 的序列化和反序列化中排除哪些字段。要使用@Expose,我们需要像这样创建 Gson 对象:

 Gson gson = new GsonBuilder()
			.excludeFieldsWithoutExposeAnnotation()
			.create(); 

如果.excludeFieldsWithoutExposeAnnotation()模式被启用,所有没有@Expose的字段将被排除。举个例子,

 import com.google.gson.annotations.Expose;

public class Staff {

    @Expose(serialize = true, deserialize = true)
    private String name;
    @Expose
    private int age;
    @Expose(serialize = false, deserialize = true)

    private String[] position;              
    private List<String> skills;            
    private Map<String, BigDecimal> salary; 

如果将上面的 Java 对象转换成 JSON,输出将是这样的

 {
  "name": "mkyong",
  "age": 35
} 

6.3 根据ExclusionStrategies、注释、类型、字段名等排除字段。Gson 是灵活的。

自定义注释@ExcludeField

ExcludeField.java

 package com.mkyong;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface ExcludeField {
} 

一个ExclusionStrategy来定义哪些字段应该被排除或跳过。

CustomExclusionStrategy.java

 package com.mkyong;

import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;

public class CustomExclusionStrategy implements ExclusionStrategy {

    private final Class<?> typeToSkip;

    public CustomExclusionStrategy(Class<?> typeToSkip) {
        this.typeToSkip = typeToSkip;
    }

    @Override
    public boolean shouldSkipField(FieldAttributes f) {

        // if field name 'salary`, skip
        if ("salary".equals(f.getName())) {
            return true;
        }

        // if found @ExcludeField, skip
        if (f.getAnnotation(ExcludeField.class) != null) {
            return true;
        }

        return false;
    }

    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return (clazz == typeToSkip);
    }

} 

再次查看staff对象。

Staff.java

 public class Staff {

    private String name;
    private int age;
    @ExcludeField
    private String[] position;
    private List<String> skills;
    private Map<String, BigDecimal> salary; 

启用ExclusionStrategy模式。

 Gson gson = new GsonBuilder()
		.setExclusionStrategies(new CustomExclusionStrategy(List.class)) // exclude all List fields.
		.create(); 

输出,本例中,字段名salary@ExcludeField字段和List类型字段将被排除。

 {"name":"mkyong","age":35} 

7.空对象支持

null对象字段被忽略。

GsonExample5.java

 package com.mkyong;

import com.google.gson.Gson;

public class GsonExample5 {

    public static void main(String[] args) {

        Gson gson = new Gson();

        Staff staff = createStaffObject();

        String json = gson.toJson(staff);

        System.out.println(json);

    }

    private static Staff createStaffObject() {

        Staff staff = new Staff();

        staff.setName("mkyong");
        staff.setAge(35);

        return staff;

    }

} 

输出

 {"name":"mkyong","age":35} 

显示空值。

 Gson gson = new GsonBuilder().serializeNulls().create(); 

输出

 {"name":"mkyong","age":35,"position":null,"skills":null,"salary":null} 

8.JSON 字段命名支持

默认

 public class Staff {

    private String name; 

输出

 {"name":"abc"} 

@SerializedName自定义字段名

 public class Staff {

    @SerializedName("mkyong_name")
    private String name; 

输出

 {"mkyong_name":"abc"} 

9.版本支持

 import com.google.gson.annotations.Since;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class Staff {

    @Since(1.0)
    private String name;

    @Since(2.0)
    private int age;

    @Since(3.0)
    private String[] position;

    private List<String> skills;
    private Map<String, BigDecimal> salary; 

在本例中,字段position(版本 3)将被排除。

 Gson gson = new GsonBuilder()
                .serializeNulls()
                .setVersion(2.0) // version <= 2.0 will be included.
                .create(); 

输出

 {"name":null,"age":0,"skills":null,"salary":null} 

10.常见问题

一些常见的问题。

10.1 使用TypeToken将 JSON 数组转换为对象列表

GsonExample4.java

 package com.mkyong;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.util.List;

public class GsonExample4 {

    public static void main(String[] args) {

        Gson gson = new Gson();
        String json = "[{\"name\":\"mkyong\"}, {\"name\":\"laplap\"}]";
        List<Staff> list = gson.fromJson(json, new TypeToken<List<Staff>>() {}.getType());
        list.forEach(x -> System.out.println(x));

    }

} 

输出

 Staff{name='mkyong', age=0, position=null, skills=null, salary=null}
Staff{name='laplap', age=0, position=null, skills=null, salary=null} 

10.2 将一个 JSON 转换成一个Map

GsonExample5.java

 package com.mkyong;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.util.Map;

public class GsonExample5 {

    public static void main(String[] args) {

        Gson gson = new Gson();

        String json = "{\"name\":\"mkyong\", \"age\":33}";
        Map<String, Object> map = gson.fromJson(json, new TypeToken<Map<String, Object>>() {}.getType());
        map.forEach((x, y) -> System.out.println("key : " + x + " , value : " + y));

    }

} 

输出

 key : name , value : mkyong
key : age , value : 33.0 

Note
Read more Gson user guide

参考

如何将新的隐藏价值传递给 JSF 的 backing bean

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/how-to-pass-new-hidden-value-to-backing-bean-in-jsf/

在某些情况下,您可能需要向后备 bean 传递一个新的隐藏值。一般有两种方式:

1.HTML 标记+ getRequestParameterMap()

通过 getRequestParameterMap() 方法,使用普通 HTML 输入、硬编码的新隐藏值和后台 bean 中的访问来呈现隐藏字段。

JSF…

 <h:form id="myForm">
    <input type="hidden" name="hidden1" value="this is hidden2" />
    <h:commandButton value="submit" action="#{user.action}" />
</h:form> 

受管 bean…

 @ManagedBean(name="user")
@SessionScoped
public class UserBean
{
	public String action(){
	   String value = FacesContext.getCurrentInstance().
		getExternalContext().getRequestParameterMap().get("hidden1");
	}
} 

2.JSF 标签+ JavaScript

通过“h:inputHidden”标记呈现隐藏字段,通过 JavaScript 分配新值。

JSF…

 <script type="text/javascript">
   function setHiddenValue(new_value){

	document.getElementById('myForm:hidden2').value = new_value;

   }
</script>
<h:form id="myForm">		    
   <h:inputHidden id="hidden2" value="#{user.hidden2}" />
   <h:commandButton value="submit" action="..." onclick="setHiddenValue('this is hidden2');" />
</h:form> 

受管 bean…

 @ManagedBean(name="user")
@SessionScoped
public class UserBean
{
	public String hidden2;

	public void setHidden2(String hidden2) {
		this.hidden2 = hidden2;
	}
} 

JSF 2.0 新隐藏价值示例

一个 JSF 2.0 的例子,演示了使用上述两种方法来传递一个新的隐藏值给一个后台 bean。

1.受管 Bean

一个简单的受管 bean,将名称指定为“user”。

 package com.mkyong.form;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;

import java.io.Serializable;

@ManagedBean(name="user")
@SessionScoped
public class UserBean implements Serializable {

	public String hidden1;
	public String hidden2;

	public String getHidden2() {
		return hidden2;
	}

	public void setHidden2(String hidden2) {
		this.hidden2 = hidden2;
	}

	public String getHidden1() {
		return hidden1;
	}

	public void setHidden1(String hidden1) {
		this.hidden1 = hidden1;
	}

	public String action(){

	    String value = FacesContext.getCurrentInstance().
		getExternalContext().getRequestParameterMap().get("hidden1");
	    setHidden1(value);

	    return "start";
	}	
} 

2.查看页面

两页用于演示。

demo . XHTML–传递新隐藏值的两种方法。

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html    
      xmlns:h="http://java.sun.com/jsf/html">

	<h:head>
	<script type="text/javascript">
	   function setHiddenValue(new_value){

	     document.getElementById('myForm:hidden2').value = new_value;

	   }
	</script>
	</h:head>
    <h:body>
     <h1>JSF 2 pass new hidden value to backing bean</h1>

     <h:form id="myForm">

       <input type="hidden" name="hidden1" value="this is hidden2" />

       <h:inputHidden id="hidden2" value="#{user.hidden2}" />

       <h:commandButton value="submit" action="#{user.action}" 
                               onclick="setHiddenValue('this is hidden2');" />
     </h:form>

    </h:body>
</html> 

start . XHTML–通过“h:outputText”标签显示隐藏值。

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html    
      xmlns:h="http://java.sun.com/jsf/html">

    <h:body>
    	<h1>JSF 2 pass new hidden value to backing bean</h1>
 	<ol>
 	  <li>Hidden1 = <h:outputText value="#{user.hidden1}" /></li>
 	  <li>Hidden2 = <h:outputText value="#{user.hidden2}" /></li>
	</ol>
    </h:body>
</html> 

3.演示

URL:http://localhost:8080/Java server faces/

jsf2-new-hidden-example-1jsf2-new-hidden-example-2

下载源代码

Download It – JSF-2-New-HiddenValue-Example.zip (10KB)

参考

  1. JSF < h:输入隐藏/ > JavaDoc

靠山豆 隐藏值JSF 2

如何在方法表达式中传递参数–JSF 2.0

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/how-to-pass-parameters-in-method-expression-jsf-2-0/

从 JSF 2.0 开始,允许在类似" #{bean.method(param)} "的方法表达式中传递参数值,但是这个特性会在 Tomcat 服务器上引发" EL 解析错误"。举个例子,

被管理的 Bean

 @ManagedBean(name="order")
@SessionScoped
public class OrderBean implements Serializable{

	public String editAction(String id) {
		//...
	}
} 

JSF 页面

 //...
<h:commandLink value="Edit" action="#{order.editAction(123)}" />
//... 

如果部署在 Tomcat 上,它将显示以下错误消息:

 An Error Occurred:
Error Parsing: #{order.editAction(123)} 

或者

 javax.el.MethodNotFoundException 

解决办法

实际上,这个所谓的方法表达式参数EL 2.2的一个特性,也就是在 Tomcat 中默认不支持

为了使用这个特性,你必须从 Java.net 的那里获得“ el-impl-2.2.jar ”,并把它放到你的项目依赖文件夹中。

文件:pom.xml

 <dependency>
	  <groupId>org.glassfish.web</groupId>
	  <artifactId>el-impl</artifactId>
	  <version>2.2</version>
     </dependency> 

做完了,Tomcat 应该可以支持 JSF 2.0 web 应用中的方法表达式参数

jsf2 parameter

如何向 JSF 2.0 模板文件传递参数?

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/how-to-pass-parameters-to-jsf-2-0-template-file/

在 JSF 2.0 web 应用程序中,您可以使用" ui:param " facelets 标记将参数传递给包含文件或模板文件。

1.“ui:include”中的参数

向包含文件传递“标签行”参数的示例。

 <ui:insert name="header" >
   <ui:include src="/template/common/commonHeader.xhtml">

	<ui:param name="tagLine" value="JSF a day, bug away" />

   </ui:include>
</ui:insert> 

commonHeader.xhtml 文件中,可以用普通的 EL 表达式访问“tagLine”参数。

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html    
      xmlns:ui="http://java.sun.com/jsf/facelets"
      >
    <body>
        <ui:composition>
	    <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>

<script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script><h2>Tag Line : #{tagLine}</h2>
	</ui:composition>
    </body>
</html> 

2.“ui:合成”中的参数

将“curFileName”参数传递给模板文件的示例。

 <ui:composition template="template/common/commonLayout.xhtml">

	<ui:param name="curFileName" value="default.xhtml" />

</ui:composition> 

commonLayout.xhtml 文件中,可以用普通的 EL 表达式访问“curFileName”参数。

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html    
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      >
    <h:body>

	<div id="content">
	        Current File : #{curFileName}
	</div>

    </h:body>
</html> 

下载源代码

Download It – JSF-2-Parameter-In-Template-Example.zip (12KB)

参考

  1. JSFui:param/JavaDoc

JSF 2参数 (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190224144307/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

如何在 Struts 2 中预选单选按钮值

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/struts2/how-to-preselect-a-radio-button-value-in-struts-2/

Download It – Struts2-Radio-Button-Example.zip

这里有几个 Struts 2 的例子来演示如何为一个单选按钮预先选择一个默认值,这个默认值是通过列表、OGNL 和对象生成的。

1.目录

在 Java 代码中,创建一个列表来返回单选按钮的值。

 //...
	List<String> genders = new ArrayList<String>();
		genders.add("male");
		genders.add("female");
		genders.add("unknown");
	//...
	public List<String> getGenders() {
		return genders;
	}
	public String getDefaultGenderValue(){
		return "unknown";
	}
	//... 

在结果页面的标签中, list="genders" 将调用 getGenders() 方法来返回单选按钮的键和值的列表。并且value = " defaultGenderValue "会调用 getDefaultGenderValue() 方法来预选“未知”值作为单选按钮的默认值

 <s:radio label="Gender" name="yourGender" list="genders" value="defaultGenderValue" /> 

它将生成以下 HTML 代码…

 <input type="radio" name="yourGender" id="resultAction_yourGendermale" value="male"/>
<label for="resultAction_yourGendermale">male</label> 

<input type="radio" name="yourGender" id="resultAction_yourGenderfemale" value="female"/>
<label for="resultAction_yourGenderfemale">female</label> 

<input type="radio" name="yourGender" id="resultAction_yourGenderunknown" 
   checked="checked" value="unknown"/>
<label for="resultAction_yourGenderunknown">unknown</label> 

2.OGNL

在结果页面中,通过 OGNL 表达式创建一个单选按钮,预选“2”作为默认值

 <s:radio label="Answer" name="yourAnswer" list="#{'1':'Yes','2':'No'}" value="2" /> 

它将生成以下 HTML 代码…

 <input type="radio" name="yourAnswer" id="resultAction_yourAnswer1" value="1"/>
<label for="resultAction_yourAnswer1">Yes</label> 

<input type="radio" name="yourAnswer" id="resultAction_yourAnswer2" 
checked="checked" value="2"/>
<label for="resultAction_yourAnswer2">No</label> 

3.目标

在 Java 代码中,使用 languageCode 和 languageDisplay 属性创建一个语言对象。

 //...
        public class Language{

	       private String languageCode;
	       private String languageDisplay;
	       //getter and setter methods
        } 
 //...
	List<Language> languages = new ArrayList<Language>();
		languages.add( new Language("EN", "English") );
		languages.add( new Language("FR", "France") );
		languages.add( new Language("CN_ZH", "Chinese") );
		languages.add( new Language("DE", "German") );
	//...
	public List<Language> getLanguages() {
		return languages;
	}
	public String getDefaultLanguageValue(){
		return "CN_ZH";
	}
	//... 

在结果页面的标签中, list="languages" 将调用 getLanguages() 方法来返回单选按钮的键和值的列表。 listKey="languageCode" 表示该语言的 languageCode 属性为单选按钮的按键;list value = " languageDisplay "将语言的 Language display 属性指定为单选按钮的值。最后一个value = " defaultLanguageValue "会调用getDefaultLanguageValue()方法来预选“CN_ZH”作为单选按钮的默认值

 <s:radio label="Gender" name="yourLanguage" list="languages" 
 listKey="languageCode" listValue="languageDisplay" value="defaultLanguageValue" /> 

它将生成以下 HTML 代码…

 <input type="radio" name="yourLanguage" id="resultAction_yourLanguageEN" value="EN"/>
<label for="resultAction_yourLanguageEN">English</label> 

<input type="radio" name="yourLanguage" id="resultAction_yourLanguageFR" value="FR"/>
<label for="resultAction_yourLanguageFR">France</label> 

<input type="radio" name="yourLanguage" id="resultAction_yourLanguageCN_ZH" 
checked="checked" value="CN_ZH"/>
<label for="resultAction_yourLanguageCN_ZH">Chinese</label> 

<input type="radio" name="yourLanguage" id="resultAction_yourLanguageDE" value="DE"/>
<label for="resultAction_yourLanguageDE">German</label> 

参考

  1. http://struts.apache.org/2.0.11.2/docs/radio.html
  2. http://struts . Apache . org/2 . 1 . 8 . 1/docs/struts-2-form-tags . html
  3. 在 Struts 2 中创建一个单选按钮

radio button struts2

如何防止 XML 外部实体攻击(XXE 攻击)

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-prevent-xml-external-entity-attack-xxe-attack/

这篇文章讨论了 XML 外部实体攻击(XXE 攻击)以及如何防止 XXE 从流行的 XML 解析器(如 DOM、SAX、JDOM 等)列表中删除。

1。什么是 XML 外部实体攻击(XXE 攻击)

XML 外部实体攻击(也称为 XXE 攻击)是针对解析包含外部实体的 XML 数据的应用程序的攻击。XML 解析器将从服务器文件系统或网络加载外部实体的内容,这可能导致任意文件泄漏或服务器端请求伪造(SSRF) 漏洞。


CWE-611

2。XXE 攻击的例子

此示例显示了如何使用 XXE 攻击来检索服务器上的文件内容。

2.1 应用程序解析下面的 XML 文件,获取员工 id 并显示员工姓名。

staff.xml

 <?xml version="1.0" encoding="utf-8"?>
  <company>
    <staffId>1001</staffId>
  </company> 

输出

 <?xml version="1.0" encoding="utf-8"?>
  <company>
    <staffId>Yong Mook Kim</staffId>
  </company> 

2.2 现在,攻击者操纵传入的 XML 文件的内容,用引用服务器文件/etc/passwd的恶意外部实体替换 XML 数据。

staff.xml

 <?xml version="1.0" encoding="UTF-8"?>
  <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
  <company>
      <staffId>&xxe;</staffId>
  </company> 

XML 解析器在解析上述恶意外部实体时,会在相应位置包含文件/etc/passwd内容。对于弱配置的 XML 解析器(通常是默认的 XML 解析器),&xxe;实体将被文件/etc/passwd的内容替换。

输出

 <?xml version="1.0" encoding="utf-8"?>
  <company>
    <staffId>nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false
    root:*:0:0:System Administrator:/var/root:/bin/sh
    daemon:*:1:1:System Services:/var/root:/usr/bin/false
    </staffId>
  </company> 

这里有一个易受 XXE 攻击的 SAX XML 解析器。

ReadXmlSaxParserXXE.java

 package com.mkyong.xml.sax;

import com.mkyong.xml.sax.handler.PrintAllHandlerSax;
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 ReadXmlSaxParserXXE {

  private static final String FILENAME = "src/main/resources/staff.xml";

  public static void main(String[] args) {

      SAXParserFactory factory = SAXParserFactory.newInstance();

      try {

          // XXE attack
          SAXParser saxParser = factory.newSAXParser();

          PrintAllHandlerSax handler = new PrintAllHandlerSax();

          saxParser.parse(FILENAME, handler);

      } catch (ParserConfigurationException | SAXException | IOException e) {
          e.printStackTrace();
      }

  }

} 

3。如何在 SAX 解析器中防止 XXE 攻击

我们可以对 SAX 解析器使用setFeature来完全禁用 DOCTYPE 声明。

 SAXParserFactory factory = SAXParserFactory.newInstance();

  try {

      // https://rules.sonarsource.com/java/RSPEC-2755
      // prevent XXE, completely disable DOCTYPE declaration:
      factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

      SAXParser saxParser = factory.newSAXParser();

      PrintAllHandlerSax handler = new PrintAllHandlerSax();

      saxParser.parse(FILENAME, handler);

  } catch (ParserConfigurationException | SAXException | IOException e) {
      e.printStackTrace();
  } 

现在,如果 SAX 解析器解析任何外部实体,它将提示一个错误:

输出

Terminal

 org.xml.sax.SAXParseException; staffId: file:///Users/yongmookkim/projects/core-java/java-xml/src/main/resources/staff-xxe.xml;
 lineNumber: 2; columnNumber: 10; DOCTYPE is disallowed
 when the feature "http://apache.org/xml/features/disallow-doctype-decl" set to true. 

4。在 XML 解析器中防止 XXE 攻击的声纳规则

回顾一下这个 Sonar 规则——XML 解析器不应该容易受到 XXE 攻击,以获得流行 XML 解析器列表的完整解决方案。

对于 DOM 解析器

 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  // to be compliant, completely disable DOCTYPE declaration:
  factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
  // or completely disable external entities declarations:
  factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
  factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
  // or prohibit the use of all protocols by external entities:
  factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
  factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
  // or disable entity expansion but keep in mind that this doesn't prevent fetching external entities
  // and this solution is not correct for OpenJDK < 13 due to a bug: https://bugs.openjdk.java.net/browse/JDK-8206132
  factory.setExpandEntityReferences(false); 

For SAX 解析器

 SAXParserFactory factory = SAXParserFactory.newInstance();
  // to be compliant, completely disable DOCTYPE declaration:
  factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
  // or completely disable external entities declarations:
  factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
  factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
  // or prohibit the use of all protocols by external entities:
  SAXParser parser = factory.newSAXParser(); // Noncompliant
  parser.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
  parser.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); 

XMLInput变压器模式

 XMLInputFactory factory = XMLInputFactory.newInstance();
  // to be compliant, completely disable DOCTYPE declaration:
  factory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
  // or completely disable external entities declarations:
  factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
  // or prohibit the use of all protocols by external entities:
  factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
  factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");

  TransformerFactory factory = javax.xml.transform.TransformerFactory.newInstance();
  // to be compliant, prohibit the use of all protocols by external entities:
  factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
  factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");

  SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
  // to be compliant, completely disable DOCTYPE declaration:
  factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
  // or prohibit the use of all protocols by external entities:
  factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
  factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); 

对于 Dom4j 库:

 SAXReader xmlReader = new SAXReader();
  xmlReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); 

对于 JDOM

 SAXBuilder builder = new SAXBuilder();
  builder.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
  builder.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); 

5。下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-xml

$ CD src/main/Java/com/mkyong/XML/sax/

6。参考文献

如何在 Java 中读取和解析 CSV 文件

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-read-and-parse-csv-file-in-java/

A CSV file

本文展示了如何读取和解析一个逗号分隔值(CSV) 文件。

主题:

  1. CSV 文件和 RFC 4180
  2. open CSV–读取并解析 CSV 文件
  3. open CSV–将 CSV 文件转换为对象
  4. 解析 CSV 文件挑战–嵌入逗号、双引号和换行符
  5. 读取和解析 CSV 文件的单个类
  6. String#split 解析 CSV 文件

1。CSV 文件和 RFC 4180。

逗号分隔值(CSV)文件是使用comma分隔值的标准文本文件。文件的每一行由一个或多个字段组成,用逗号分隔。每个字段可以用双引号括起来,也可以不用。

 1995,Java,James Gosling
"1995","Java","James Gosling" 

RFC 4180 定义了 CSV 文件或text/csv文件的格式或定义。

2。open CSV–读取和解析 CSV 文件。

2.1open CSV是简单易用的 Java CSV 解析器。

pom.xml

 <dependency>
      <groupId>com.opencsv</groupId>
      <artifactId>opencsv</artifactId>
      <version>5.3</version>
  </dependency> 

2.2 然而,opencsv.jar具有如下依赖关系,如commons-lang3.jarcommons-text.jarcommons-beanutils.jarcommons-logging.jarcommons-collections4:jar

Terminal

 [INFO] \- com.opencsv:opencsv:jar:5.3:compile
[INFO]    +- org.apache.commons:commons-lang3:jar:3.11:compile
[INFO]    +- org.apache.commons:commons-text:jar:1.9:compile
[INFO]    +- commons-beanutils:commons-beanutils:jar:1.9.4:compile
[INFO]    |  +- commons-logging:commons-logging:jar:1.2:compile
[INFO]    |  \- commons-collections:commons-collections:jar:3.2.2:compile
[INFO]    \- org.apache.commons:commons-collections4:jar:4.4:compile 

附注:OpenCSV及其依赖项的总文件大小约为 2M+。

2.3OpenCSV示例读取或解析 CSV 文件。

读取全部并返回一个List<String[]>

 try (CSVReader reader = new CSVReader(new FileReader("file.csv"))) {
      List<String[]> r = reader.readAll();
      r.forEach(x -> System.out.println(Arrays.toString(x)));
  } 

逐行读取并将行转换为String[]

 try (CSVReader reader = new CSVReader(new FileReader("file.csv"))) {
      String[] lineInArray;
      while ((lineInArray = reader.readNext()) != null) {
          System.out.println(lineInArray[0] + lineInArray[1] + "etc...");
      }
  } 

解析 CSV 文件的完整OpenCSV示例。

c:\test\csv\country.csv

 "1.0.0.0","1.0.0.255","AU","Australia"
"1.0.1.0","1.0.3.255","CN","China"
"1.0.4.0","1.0.7.255","AU","Australia"
"1.0.128.0","1.0.255.255","TH","Thailand" 

OpenCsvExample.java

 package com.mkyong.io.csv.opencsv;

import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvException;

import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

public class OpenCsvExample {

    public static void main(String[] args) throws IOException, CsvException {

        String fileName = "c:\\test\\csv\\country.csv";
        try (CSVReader reader = new CSVReader(new FileReader(fileName))) {
            List<String[]> r = reader.readAll();
            r.forEach(x -> System.out.println(Arrays.toString(x)));
        }

    }

} 

输出

Terminal

 [1.0.0.0, 1.0.0.255, AU, Australia]
[1.0.1.0, 1.0.3.255, CN, China]
[1.0.4.0, 1.0.7.255, AU, Australia]
[1.0.128.0, 1.0.255.255, TH, Thailand] 

2.4 常用分号;作为分隔符。这个OpenCSV示例展示了如何使用自定义分隔符;解析 CSV 文件并跳过第一行。

 CSVParser csvParser = new CSVParserBuilder().withSeparator(';').build(); // custom separator
  try(CSVReader reader = new CSVReaderBuilder(
          new FileReader(fileName))
          .withCSVParser(csvParser)   // custom CSV parser
          .withSkipLines(1)           // skip the first line, header info
          .build()){
      List<String[]> r = reader.readAll();
      r.forEach(x -> System.out.println(Arrays.toString(x)));
  } 

注意
使用分号;作为分隔符不符合 RFC 4180 。然而,在 CSV 文件中看到分号分隔符是很常见的;不是每个人都遵循 RFC。

3。open CSV–将 CSV 文件转换为对象。

OpenCSV还支持将 CSV 文件直接读取或解析成 Java 对象。

3.1 本例读取一个 CSV 文件,并通过@CsvBindByPosition将其映射到一个Country对象。

c:\test\csv\country.csv

 "1.0.0.0","1.0.0.255","AU","Australia"
"1.0.1.0","1.0.3.255","CN","China"
"1.0.4.0","1.0.7.255","AU","Australia"
"1.0.128.0","1.0.255.255","TH","Thailand" 

Country.java

 package com.mkyong.io.csv.opencsv;

import com.opencsv.bean.CsvBindByPosition;

public class Country {

    @CsvBindByPosition(position = 0)
    private String startIp;

    @CsvBindByPosition(position = 1)
    private String endIp;

    @CsvBindByPosition(position = 2)
    private String countryCode;

    @CsvBindByPosition(position = 3)
    private String country;

    //  getters, setters, toString
} 

OpenCsvExample.java

 package com.mkyong.io.csv.opencsv;

import com.opencsv.bean.CsvToBeanBuilder;

import java.io.FileReader;
import java.io.IOException;
import java.util.List;

public class OpenCsvExample {

    public static void main(String[] args) throws IOException {

        String fileName = "c:\\test\\csv\\country.csv";

        List<Country> beans = new CsvToBeanBuilder(new FileReader(fileName))
                .withType(Country.class)
                .build()
                .parse();

        beans.forEach(System.out::println);

    }

} 

输出

Terminal

 Country{startIp='1.0.0.0', endIp='1.0.0.255', countryCode='AU', country='Australia'}
Country{startIp='1.0.1.0', endIp='1.0.3.255', countryCode='CN', country='China'}
Country{startIp='1.0.4.0', endIp='1.0.7.255', countryCode='AU', country='Australia'}
Country{startIp='1.0.128.0', endIp='1.0.255.255', countryCode='TH', country='Thailand'} 

3.2 如果 CSV 文件包含头文件信息,我们也可以使用@CsvBindByName将 CSV 文件映射到一个 Java 对象。

c:\test\csv\country.csv

 start ip,end ip,country code, country
"1.0.0.0","1.0.0.255","AU","Australia"
"1.0.1.0","1.0.3.255","CN","China"
"1.0.4.0","1.0.7.255","AU","Australia"
"1.0.128.0","1.0.255.255","TH","Thailand" 

Country.java

 package com.mkyong.io.csv.opencsv;

import com.opencsv.bean.CsvBindByName;

public class Country {

    @CsvBindByName(column = "start ip")
    private String startIp;

    @CsvBindByName(column = "end ip")
    private String endIp;

    @CsvBindByName(column = "country code")
    private String countryCode;

    @CsvBindByName
    private String country;

    //  getters, setters, toString
} 

输出

Terminal

 Country{startIp='1.0.0.0', endIp='1.0.0.255', countryCode='AU', country='Australia'}
Country{startIp='1.0.1.0', endIp='1.0.3.255', countryCode='CN', country='China'}
Country{startIp='1.0.4.0', endIp='1.0.7.255', countryCode='AU', country='Australia'}
Country{startIp='1.0.128.0', endIp='1.0.255.255', countryCode='TH', country='Thailand'} 


更多OpenCSV示例,请查看 OpenCSV 官方文档

4。CSV 和嵌入的逗号、双引号和换行符

4.1RFC 4180描述了 CSV 文件格式的定义,规则 1-5 是一些基本且易于实现的规则,真正的挑战是规则 6 和 7。

 6\. Fields containing line breaks (CRLF), double quotes, and commas
     should be enclosed in double-quotes.  For example:

     "aaa","b CRLF
     bb","ccc" CRLF
     zzz,yyy,xxx

7\.  If double-quotes are used to enclose fields, then a double-quote
     appearing inside a field must be escaped by preceding it with
     another double quote.  For example:

     "aaa","b""bb","ccc" 

4.2 表到 CVS 文件。

制造 模型 描述 价格
(里面或周围有树的)小山谷 P3421W 戴尔 34 英寸曲面 USB-C 显示器 Two thousand four hundred and ninety-nine
(里面或周围有树的)小山谷 外星人 38 曲面“游戏显示器” Six thousand six hundred and ninety-nine
三星电子 49 英寸双 QHD,QLED,HDR1000 Six thousand one hundred and ninety-nine
三星电子 升职!特价
49 英寸双 QHD,QLED,HDR1000 Four thousand nine hundred and ninety-nine

上表可以 CSV 格式表示如下:

monitor.csv

 Make,Model,Description,Price
Dell,P3421W,"Dell 34, Curved, USB-C Monitor",2499.00
Dell,"","Alienware 38 Curved ""Gaming Monitor""",6699.00
Samsung,,"49"" Dual QHD, QLED, HDR1000",6199.00
Samsung,,"Promotion! Special Price
49"" Dual QHD, QLED, HDR1000",4999.00 

4.3 用OpenCSV再次测试上述 CSV 文件,并检查结果:

 package com.mkyong.io.csv.opencsv;

import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvException;

import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

public class OpenCsvExample {

    public static void main(String[] args) throws IOException, CsvException {

        String fileName = "c:\\test\\csv\\monitor.csv";

        List<String[]> r;
        try (CSVReader reader = new CSVReader(new FileReader(fileName))) {
            r = reader.readAll();
        }

        int listIndex = 0;
        for (String[] arrays : r) {
            System.out.println("\nString[" + listIndex++ + "] : " + Arrays.toString(arrays));

            int index = 0;
            for (String array : arrays) {
                System.out.println(index++ + " : " + array);
            }

        }
    }

} 

输出

Terminal

 String[0] : [Make, Model, Description, Price]
0 : Make
1 : Model
2 : Description
3 : Price

String[1] : [Dell, P3421W, Dell 34, Curved, USB-C Monitor, 2499.00]
0 : Dell
1 : P3421W
2 : Dell 34, Curved, USB-C Monitor
3 : 2499.00

String[2] : [Dell, , Alienware 38 Curved "Gaming Monitor", 6699.00]
0 : Dell
1 :
2 : Alienware 38 Curved "Gaming Monitor"
3 : 6699.00

String[3] : [Samsung, , 49" Dual QHD, QLED, HDR1000, 6199.00]
0 : Samsung
1 :
2 : 49" Dual QHD, QLED, HDR1000
3 : 6199.00

String[4] : [Samsung, , Promotion! Special Price
49" Dual QHD, QLED, HDR1000, 4999.00]
0 : Samsung
1 :
2 : Promotion! Special Price
49" Dual QHD, QLED, HDR1000
3 : 4999.00 

上面的输出是一个完美的、精确的匹配。

5。读取和解析 CSV 文件的单个类。

5.1 如果你不想下载OpenCSV库由于文件大小太多的依赖关系,下面是我解析一个 CSV 文件的单个类实现。

包含嵌入逗号、双引号和换行符的同一个 CSV 文件。

monitor.csv

 Make,Model,Description,Price
Dell,P3421W,"Dell 34, Curved, USB-C Monitor",2499.00
Dell,"","Alienware 38 Curved ""Gaming Monitor""",6699.00
Samsung,,"49"" Dual QHD, QLED, HDR1000",6199.00
Samsung,,"Promotion! Special Price
49"" Dual QHD, QLED, HDR1000",4999.00 

解析上述 CSV 文件的单个类实现。阅读注释,了解更多信息。

CsvParserSimple.java

 package com.mkyong.io.csv;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.net.URL;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class CsvParserSimple {

    private static final char DEFAULT_SEPARATOR = ',';
    private static final char DOUBLE_QUOTES = '"';
    private static final char DEFAULT_QUOTE_CHAR = DOUBLE_QUOTES;
    private static final String NEW_LINE = "\n";

    private boolean isMultiLine = false;
    private String pendingField = "";
    private String[] pendingFieldLine = new String[]{};

    public static void main(String[] args) throws Exception {

        // loads CSV file from the resource folder.
        URL resource = CsvParserSimple.class.getClassLoader().getResource("csv/monitor.csv");
        File file = Paths.get(resource.toURI()).toFile();

        CsvParserSimple obj = new CsvParserSimple();
        List<String[]> result = obj.readFile(file, 1);

        int listIndex = 0;
        for (String[] arrays : result) {
            System.out.println("\nString[" + listIndex++ + "] : " + Arrays.toString(arrays));

            int index = 0;
            for (String array : arrays) {
                System.out.println(index++ + " : " + array);
            }

        }

    }

    public List<String[]> readFile(File csvFile) throws Exception {
        return readFile(csvFile, 0);
    }

    public List<String[]> readFile(File csvFile, int skipLine)
        throws Exception {

        List<String[]> result = new ArrayList<>();
        int indexLine = 1;

        try (BufferedReader br = new BufferedReader(new FileReader(csvFile))) {

            String line;
            while ((line = br.readLine()) != null) {

                if (indexLine++ <= skipLine) {
                    continue;
                }

                String[] csvLineInArray = parseLine(line);

                if (isMultiLine) {
                    pendingFieldLine = joinArrays(pendingFieldLine, csvLineInArray);
                } else {

                    if (pendingFieldLine != null && pendingFieldLine.length > 0) {
                        // joins all fields and add to list
                        result.add(joinArrays(pendingFieldLine, csvLineInArray));
                        pendingFieldLine = new String[]{};
                    } else {
                        // if dun want to support multiline, only this line is required.
                        result.add(csvLineInArray);
                    }

                }

            }
        }

        return result;
    }

    public String[] parseLine(String line) throws Exception {
        return parseLine(line, DEFAULT_SEPARATOR);
    }

    public String[] parseLine(String line, char separator) throws Exception {
        return parse(line, separator, DEFAULT_QUOTE_CHAR).toArray(String[]::new);
    }

    private List<String> parse(String line, char separator, char quoteChar)
        throws Exception {

        List<String> result = new ArrayList<>();

        boolean inQuotes = false;
        boolean isFieldWithEmbeddedDoubleQuotes = false;

        StringBuilder field = new StringBuilder();

        for (char c : line.toCharArray()) {

            if (c == DOUBLE_QUOTES) {               // handle embedded double quotes ""
                if (isFieldWithEmbeddedDoubleQuotes) {

                    if (field.length() > 0) {       // handle for empty field like "",""
                        field.append(DOUBLE_QUOTES);
                        isFieldWithEmbeddedDoubleQuotes = false;
                    }

                } else {
                    isFieldWithEmbeddedDoubleQuotes = true;
                }
            } else {
                isFieldWithEmbeddedDoubleQuotes = false;
            }

            if (isMultiLine) {                      // multiline, add pending from the previous field
                field.append(pendingField).append(NEW_LINE);
                pendingField = "";
                inQuotes = true;
                isMultiLine = false;
            }

            if (c == quoteChar) {
                inQuotes = !inQuotes;
            } else {
                if (c == separator && !inQuotes) {  // if find separator and not in quotes, add field to the list
                    result.add(field.toString());
                    field.setLength(0);             // empty the field and ready for the next
                } else {
                    field.append(c);                // else append the char into a field
                }
            }

        }

        //line done, what to do next?
        if (inQuotes) {
            pendingField = field.toString();        // multiline
            isMultiLine = true;
        } else {
            result.add(field.toString());           // this is the last field
        }

        return result;

    }

    private String[] joinArrays(String[] array1, String[] array2) {
        return Stream.concat(Arrays.stream(array1), Arrays.stream(array2))
                .toArray(String[]::new);
    }
} 

输出。

Terminal

 String[0] : [Dell, P3421W, Dell 34, Curved, USB-C Monitor, 2499.00]
0 : Dell
1 : P3421W
2 : Dell 34, Curved, USB-C Monitor
3 : 2499.00

String[1] : [Dell, , Alienware 38 Curved "Gaming Monitor", 6699.00]
0 : Dell
1 :
2 : Alienware 38 Curved "Gaming Monitor"
3 : 6699.00

String[2] : [Samsung, , 49" Dual QHD, QLED, HDR1000, 6199.00]
0 : Samsung
1 :
2 : 49" Dual QHD, QLED, HDR1000
3 : 6199.00

String[3] : [Samsung, , Promotion! Special Price
49" Dual QHD, QLED, HDR1000, 4999.00]
0 : Samsung
1 :
2 : Promotion! Special Price
49" Dual QHD, QLED, HDR1000
3 : 4999.00 

输出是正确的。

5.3 阅读下面不同类型 CSV 文件的单元测试。

CsvParserSimpleTest.java

 package com.mkyong.io.csv;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class CsvParserSimpleTest {

    private CsvParserSimple parser = new CsvParserSimple();
    // OpenCSV
    //private CSVParser parser = new CSVParser();

    @ParameterizedTest(name = "#{index} - Run test with args={0}")
    @ValueSource(strings = {
            "\"aa\",\"bb\",\"cc\",\"dd\",\"ee\"",
            "aa,bb,cc,dd,ee",
            "aa,bb,\"cc\",dd,ee"
    }
    )
    void test_csv_line_default(String line) throws Exception {
        String[] result = parser.parseLine(line);
        assertEquals(5, result.length);
        assertEquals("aa", result[0]);
        assertEquals("bb", result[1]);
        assertEquals("cc", result[2]);
        assertEquals("dd", result[3]);
        assertEquals("ee", result[4]);
    }

    @ParameterizedTest(name = "#{index} - Run test with args={0}")
    @ValueSource(strings = {
            "\"aa\",\"\",\"\",\"\",\"\"",
            "aa,,,,",
            "aa,,\"\",,"
    }
    )
    void test_csv_line_empty(String line) throws Exception {
        String[] result = parser.parseLine(line);
        assertEquals(5, result.length);
        assertEquals("aa", result[0]);
        assertEquals("", result[1]);
        assertEquals("", result[2]);
        assertEquals("", result[3]);
        assertEquals("", result[4]);
    }

    // RFC 4180 require comma as separator, but in real life , it can be a semicolon,
    // not everyone follows RFC.
    @ParameterizedTest(name = "#{index} - Run test with args={0}")
    @ValueSource(strings = {
            "\"aa\";\"bb\";\"cc\";\"dd\";\"ee\"",
            "aa;bb;cc;dd;ee",
            "aa;bb;\"cc\";dd;ee"
    }
    )
    void test_csv_line_custom_separator(String line) throws Exception {
        String[] result = parser.parseLine(line, ';');
        assertEquals(5, result.length);
        assertEquals("aa", result[0]);
        assertEquals("bb", result[1]);
        assertEquals("cc", result[2]);
        assertEquals("dd", result[3]);
        assertEquals("ee", result[4]);
    }

    @ParameterizedTest(name = "#{index} - Run test with args={0}")
    @ValueSource(strings = {
            "\"Australia\",\"11 Lakkari Cl, Taree, NSW 2430\"",
            "Australia,\"11 Lakkari Cl, Taree, NSW 2430\""
    }
    )
    void test_csv_line_contain_comma_in_field(String line) throws Exception {

        String[] result = parser.parseLine(line);

        assertEquals(2, result.length);
        assertEquals("Australia", result[0]);
        assertEquals("11 Lakkari Cl, Taree, NSW 2430", result[1]);

    }

    @Test
    void test_csv_line_contain_double_quotes_in_field() throws Exception {

        String line = "\"Australia\",\"51 Maritime Avenue, \"\"Western Australia\"\", 6286\"";
        String[] result = parser.parseLine(line);

        assertEquals(2, result.length);
        assertEquals("Australia", result[0]);
        assertEquals("51 Maritime Avenue, \"Western Australia\", 6286", result[1]);

    }

    @Test
    void test_csv_line_contain_double_quotes_in_field_2() throws Exception {

        String line = "Australia,Welcome to \"\"Western Australia\"\"";
        String[] result = parser.parseLine(line);

        assertEquals(2, result.length);
        assertEquals("Australia", result[0]);
        assertEquals("Welcome to \"Western Australia\"", result[1]);

    }

    /*
    private File getFileFromTestResourcesFolder(String fileName) throws URISyntaxException {
        // get uri from the test resources folder.
        URL resource = CsvParserMyImplTest.class.getClassLoader().getResource(fileName);
        File file = Paths.get(resource.toURI()).toFile();
        return file;
    }*/
} 

Parse CSV Unit Tests

检查结果和单元测试;CsvParserSimple应该读取或解析大多数标准 CSV 文件。

6。String#split 解析 CSV 文件。

6.1 问:我可以使用String#split来解析一个简单的 CSV 文件吗?
是的,如果你确定,CSV 文件格式简单明了,不包含任何嵌入的逗号、双引号和换行符,如上面的解析 CSV 文件挑战所述。

country.csv

 "1.0.0.0","1.0.0.255","AU","Australia"
"1.0.1.0","1.0.3.255","CN","China"
"1.0.4.0","1.0.7.255","AU","Australia"
"1.0.128.0","1.0.255.255","TH","Thailand" 

6.2 Java 8 流和拆分示例解析上述 CSV 文件。

 List<String[]> collect =
          Files.lines(Paths.get("c:\\test\\csv\\country.csv"))
                .map(line -> line.split(","))
                .collect(Collectors.toList()); 

输出

Terminal

 ["1.0.0.0", "1.0.0.255", "AU", "Australia"]
["1.0.1.0", "1.0.3.255", "CN", "China"]
["1.0.4.0", "1.0.7.255", "AU", "Australia"]
["1.0.128.0", "1.0.255.255", "TH", "Thailand"] 

6.3 这里是老派风格。

 String line;
  try (BufferedReader br = new BufferedReader(
          new FileReader("c:\\test\\csv\\country.csv"))) {

      while ((line = br.readLine()) != null) {

          // split by a comma separator
          String[] split = line.split(",");
          System.out.println("\nLength : " + split.length);
          System.out.println("split[0] : " + split[0]);
          System.out.println("split[1] : " + split[1]);
          System.out.println("split[2] : " + split[2]);
          System.out.println("split[3] : " + split[3]);
      }

  } catch (IOException e) {
      e.printStackTrace();
  } 

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ Java-io/CSV CD

参考文献

如何在 Java 中读取文件

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-read-file-from-java-bufferedreader-example/

在本文中,我们将向您展示如何使用java.io.BufferedReader从文件中读取内容

Note
Read this different ways read a file

1.Files.newBufferedReader (Java 8)

在 Java 8 中,有一个新的方法Files.newBufferedReader(Paths.get("file"))来返回一个BufferedReader

filename.txt

 A
B
C
D
E 

FileExample1.java

 package com.mkyong;

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class FileExample1 {

    public static void main(String[] args) {

        StringBuilder sb = new StringBuilder();

        try (BufferedReader br = Files.newBufferedReader(Paths.get("filename.txt"))) {

            // read line by line
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line).append("\n");
            }

        } catch (IOException e) {
            System.err.format("IOException: %s%n", e);
        }

        System.out.println(sb);

    }

} 

输出

 A
B
C
D
E 

2.缓冲阅读器

2.1 经典的BufferedReader与 JDK 1.7 try-with-resources自动关闭资源。

FileExample2.java

 package com.mkyong;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class FileExample2 {

    public static void main(String[] args) {

        try (FileReader reader = new FileReader("filename.txt");
             BufferedReader br = new BufferedReader(reader)) {

            // read line by line
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }

        } catch (IOException e) {
            System.err.format("IOException: %s%n", e);
        }
    }

} 

2.2 在过去,我们必须手动关闭所有内容。

FileExample3.java

 package com.mkyong.calculator;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class FileExample3 {

    public static void main(String[] args) {

        BufferedReader br = null;
        FileReader fr = null;

        try {

            fr = new FileReader("filename.txt");
            br = new BufferedReader(fr);

            // read line by line
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }

        } catch (IOException e) {
            System.err.format("IOException: %s%n", e);
        } finally {
            try {
                if (br != null)
                    br.close();

                if (fr != null)
                    fr.close();
            } catch (IOException ex) {
                System.err.format("IOException: %s%n", ex);
            }
        }

    }

} 

参考

如何在 Java 中读取文件–file inputstream

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

在 Java 中,我们使用 FileInputStream 从文件中读取字节,比如图像文件或二进制文件。

主题

  1. 文件输入流–读取文件
  2. 文件输入流–剩余字节
  3. 文件输入流–更好的性能
  4. 文件输入流 vs 缓冲输入流
  5. InputStreamReader–将文件输入流转换为阅读器
  6. FileInputStream – Read a Unicode file

注意
然而,下面所有的例子都使用FileInputStream从文本文件中读取字节并打印出来。文本文件允许读者正确地“看到”输出。通常,我们使用Reader从文本文件中读取字符。

1。file inputstream–读取文件

这个例子使用FileInputStream从文件中读取字节并打印出内容。fis.read()一次读取一个字节,如果到达文件末尾,它将返回一个-1

FileInputStreamExample1.java

 package com.mkyong.io.api.inputstream;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class FileInputStreamExample1 {

    public static void main(String[] args) {
        readFile("c:\\test\\file.txt");
    }

    private static void readFile(String fileName) {

        try (FileInputStream fis = new FileInputStream(new File(fileName))) {
            int content;
            // reads a byte at a time, if it reached end of the file, returns -1
            while ((content = fis.read()) != -1) {
                System.out.println((char)content);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

} 

2。文件输入流–剩余字节

我们可以使用fis.available()来检查剩余的可以读取的字节。例如:

下面是一个包含 10 个字节的文本文件。

c:\test\file.txt

 mkyong.com 

read fileFileInputStreamExample2.java

 package com.mkyong.io.api.inputstream;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class FileInputStreamExample2 {

    public static void main(String[] args) {
        readFile("c:\\test\\file.txt");
    }

    private static void readFile(String fileName) {

        try (FileInputStream fis = new FileInputStream(new File(fileName))) {

            // remaining bytes that can be read
            System.out.println("Remaining bytes that can be read : " + fis.available());

            int content;
            // reads a byte at a time, if end of the file, returns -1
            while ((content = fis.read()) != -1) {
                System.out.println((char) content);

                System.out.println("Remaining bytes that can be read : " + fis.available());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

} 

输出

Terminal

 Remaining bytes that can be read : 10
m
Remaining bytes that can be read : 9
k
Remaining bytes that can be read : 8
y
Remaining bytes that can be read : 7
o
Remaining bytes that can be read : 6
n
Remaining bytes that can be read : 5
g
Remaining bytes that can be read : 4
.
Remaining bytes that can be read : 3
c
Remaining bytes that can be read : 2
o
Remaining bytes that can be read : 1
m
Remaining bytes that can be read : 0 

对于一个包含 10 个字节的文件,fis.read()将运行十次,每次读取一个字节。(看到这里的问题?)

3。文件输入流–更好的性能

3.1 查看FileInputStream#read()源代码,每个read()都会调用native方法从磁盘中读取一个字节。

 package java.io;

public class FileInputStream extends InputStream {

    /**
     * Reads a byte of data from this input stream. This method blocks
     * if no input is yet available.
     *
     * @return     the next byte of data, or <code>-1</code> if the end of the
     *             file is reached.
     * @exception  IOException  if an I/O error occurs.
     */
    public int read() throws IOException {
        return read0();
    }

    private native int read0() throws IOException;

    //...
} 

3.2 我们可以使用read(byte b[])将预定义的字节读入一个字节数组;这将显著提高读取性能。

FileInputStreamExample3.java

 package com.mkyong.io.api.inputstream;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class FileInputStreamExample3 {

    public static void main(String[] args) {
        readFileBetterPerformance("c:\\test\\file.txt");
    }

    private static void readFileBetterPerformance(String fileName) {

        try (FileInputStream fis = new FileInputStream(new File(fileName))) {

            // remaining bytes that can be read
            System.out.println("Remaining bytes that can be read : " + fis.available());

            // 8k a time
            byte[] bytes = new byte[8192];

            // reads 8192 bytes at a time, if end of the file, returns -1
            while (fis.read(bytes) != -1) {

                // convert bytes to string for demo
                System.out.println(new String(bytes, StandardCharsets.UTF_8));

                System.out.println("Remaining bytes that can be read : " + fis.available());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

} 

上面的例子会一次读取8192个字节,对于一个包含 10 个字节的文件,只读取一次。

Terminal

 Remaining bytes that can be read : 10
mkyong.com
Remaining bytes that can be read : 0 

注意例如
,如果一个文件包含81920个字节(80 kb),默认fis.read将需要一个 81920 本地调用来从文件中读取所有字节;而fis.read(bytes)(对于 8192 的大小),我们只需要 10 个本地调用。差别是巨大的。

4。文件输入流 vs 缓冲输入流

FileInputStream一次读取一个字节,每个read()将从磁盘进行本地读取。对于读取大文件,它会变慢。

BufferedInputStream一次读取8192个字节(默认),并缓冲它们,直到需要它们为止;BufferedInputStream#read()仍然一次返回一个字节,但是其他剩余的字节在缓冲区中,为下一次读取保留。概念类似于上面的FileInputStreamExample3.java

通常的做法是使用BufferedInputStream来包装FileInputStream以提供缓冲区缓存来提高读取性能。

FileInputStreamExample4.java

 package com.mkyong.io.api.inputstream;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class FileInputStreamExample4 {

    public static void main(String[] args) {
        readFileBetterPerformance2("c:\\test\\file.txt");
    }

    private static void readFileBetterPerformance2(String fileName) {

        try (BufferedInputStream bis =
                     new BufferedInputStream(
                             new FileInputStream(new File(fileName)))) {

            // remaining bytes that can be read
            System.out.println("Remaining bytes that can be read : " + bis.available());

            int content;
            // reads 8192 bytes at a time and buffers them until they are needed,
            // if end of the file, returns -1
            while ((content = bis.read()) != -1) {

                // convert bytes to string for demo
                System.out.println((char) content);

                System.out.println("Remaining bytes that can be read : " + bis.available());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

} 

输出

Terminal

 Remaining bytes that can be read : 10
m
Remaining bytes that can be read : 9
k
Remaining bytes that can be read : 8
y
Remaining bytes that can be read : 7
o
Remaining bytes that can be read : 6
n
Remaining bytes that can be read : 5
g
Remaining bytes that can be read : 4
.
Remaining bytes that can be read : 3
c
Remaining bytes that can be read : 2
o
Remaining bytes that can be read : 1
m
Remaining bytes that can be read : 0 

5。将文件输入流转换为阅读器

使用InputStreamReaderInputStream转换为Reader也很常见。

这个例子展示了如何将一个FileInputStream转换成BufferedReader,并逐行读取。

 private static void readFileBetterInputStreamReader(String fileName) {

    try (BufferedReader br =
                 new BufferedReader(
                         new InputStreamReader(
                                 new FileInputStream(new File(fileName))))) {

        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }

    } catch (IOException e) {
        e.printStackTrace();
    }

} 

6. FileInputStream – Read a Unicode file

这个例子使用FileInputStream来读取一个 Unicode 文件。例如:

一种包含几个中文字符的 Unicode 文件,每个 Unicode 编码字符包含两个或多个字节。

c:\test\file-unicode.txt

 你好
我好
大家好 

unicode file

我们可以使用上面的例子 3 来读取 Unicode 文件并正确打印它们。

FileInputStreamExample3.java

 private static void readFileBetterPerformance(String fileName) {

      try (FileInputStream fis = new FileInputStream(new File(fileName))) {

          // remaining bytes that can be read
          System.out.println("Remaining bytes that can be read : " + fis.available());

          // 8k a time
          byte[] bytes = new byte[8192];

          // reads 8192 bytes at a time, if end of the file, returns -1
          while (fis.read(bytes) != -1) {

              // convert bytes to string for demo

              // convert bytes unicode to string
              System.out.println(new String(bytes, StandardCharsets.UTF_8));

              System.out.println("Remaining bytes that can be read : " + fis.available());
          }
      } catch (IOException e) {
          e.printStackTrace();
      }

  } 

输出

Terminal

 Remaining bytes that can be read : 25
你好
我好
大家好
Remaining bytes that can be read : 0 

此外,我们还可以使用示例 5 InputStreamReader 来读取和打印 Unicode 文件,默认情况下InputStreamReader有一个默认的 UTF-8 字符集。

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd api/inputstream

参考文献

如何用 Java 读取 UTF 8 文件

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-read-utf-8-encoded-data-from-a-file-java/

在 Java 中, InputStreamReader 接受一个字符集来将字节流解码成字符流。我们可以向InputStreamReader构造函数传递一个StandardCharsets.UTF_8来从 UTF-8 文件中读取数据。

 import java.nio.charset.StandardCharsets;

  //...
  try (FileInputStream fis = new FileInputStream(file);
       InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
       BufferedReader reader = new BufferedReader(isr)
  ) {

      String str;
      while ((str = reader.readLine()) != null) {
          System.out.println(str);
      }

  } catch (IOException e) {
      e.printStackTrace();
  } 

在 Java 7+中,许多文件读取 API 开始接受charset作为参数,使得读取 UTF-8 变得非常容易。

 // Java 7
  BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8);

  // Java 8
  List<String> list = Files.readAllLines(path, StandardCharsets.UTF_8);

  // Java 8
  Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8);

  // Java 11
  String s = Files.readString(path, StandardCharsets.UTF_8); 

1.UTF 八号档案

一个 UTF 8 编码文件c:\\temp\\test.txt,有中文字符。

utf-8 file

2.阅读 UTF-8 文件

这个例子展示了几种读取 UTF 8 文件的方法。

 package com.mkyong.io.howto;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Stream;

public class UnicodeRead {

    public static void main(String[] args) {

        String fileName = "c:\\temp\\test.txt";

        //readUnicodeJava11(fileName);
        readUnicodeBufferedReader(fileName);
        //readUnicodeFiles(fileName);
        //readUnicodeClassic(fileName);

    }

    // Java 7 - Files.newBufferedReader(path, StandardCharsets.UTF_8)
    // Java 8 - Files.newBufferedReader(path) // default UTF-8
    public static void readUnicodeBufferedReader(String fileName) {

        Path path = Paths.get(fileName);

        // Java 8, default UTF-8
        try (BufferedReader reader = Files.newBufferedReader(path)) {

            String str;
            while ((str = reader.readLine()) != null) {
                System.out.println(str);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void readUnicodeFiles(String fileName) {

        Path path = Paths.get(fileName);
        try {

            // Java 11
            String s = Files.readString(path, StandardCharsets.UTF_8);
            System.out.println(s);

            // Java 8
            List<String> list = Files.readAllLines(path, StandardCharsets.UTF_8);
            list.forEach(System.out::println);

            // Java 8
            Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8);
            lines.forEach(System.out::println);

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    // Java 11, adds charset to FileReader
    public static void readUnicodeJava11(String fileName) {

        Path path = Paths.get(fileName);

        try (FileReader fr = new FileReader(fileName, StandardCharsets.UTF_8);
             BufferedReader reader = new BufferedReader(fr)) {

            String str;
            while ((str = reader.readLine()) != null) {
                System.out.println(str);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void readUnicodeClassic(String fileName) {

        File file = new File(fileName);

        try (FileInputStream fis = new FileInputStream(file);
             InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
             BufferedReader reader = new BufferedReader(isr)
        ) {

            String str;
            while ((str = reader.readLine()) != null) {
                System.out.println(str);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }
} 

输出

Terminal

 line 1
line 2
line 3
你好,世界 

延伸阅读
如何用 Java 写一个 UTF-8 文件

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-io

参考

如何在 Java 中读取 UTF-8 XML 文件—(SAX 解析器)

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-read-utf-8-xml-file-in-java-sax-parser/

本文展示了如何使用 SAX 解析器读取或解析 UTF-8 XML 文件。

目录

1。SAX 解析器解析 UTF-8 XML 文件。

1.1 XML 文件包含 UTF-8 和中文字符。

staff.xml

 <?xml version="1.0" encoding="utf-8"?>
<Company>
    <staff id="1001">
        <name>揚木金</name>
        <role>support &amp; code</role>
        <salary currency="USD">5000</salary>
        <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> 

1.2 下面的例子显式设置了一个UTF-8编码。


对于 SAX 处理程序PrintAllHandlerSax,参考这篇文章

ReadXmlSaxParser.java

 package com.mkyong.xml.sax;

import com.mkyong.xml.sax.handler.PrintAllHandlerSax;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class ReadXmlSaxParser {

  private static final String FILENAME = "src/main/resources/staff-unicode.xml";

  public static void main(String[] args) {

      SAXParserFactory factory = SAXParserFactory.newInstance();

      try {

          SAXParser saxParser = factory.newSAXParser();

          PrintAllHandlerSax handler = new PrintAllHandlerSax();

          XMLReader xmlReader = saxParser.getXMLReader();
          xmlReader.setContentHandler(handler);

          InputSource source = new InputSource(FILENAME);

          // explicitly set a encoding
          source.setEncoding(StandardCharsets.UTF_8.displayName());

          xmlReader.parse(source);

      } catch (ParserConfigurationException | SAXException | IOException e) {
          e.printStackTrace();
      }

  }

} 

输出

Terminal

 Start Document
Start Element : Company
Start Element : staff
Staff id : 1001
Start Element : name
End Element : name
Name : 揚木金
Start Element : role
End Element : role
Role : support & code
Start Element : salary
Currency :USD
End Element : salary
Salary : 5000
Start Element : bio
End Element : bio
Bio : HTML tag <code>testing</code>
End Element : staff
Start Element : staff
Staff id : 1002
Start Element : name
End Element : name
Name : yflow
Start Element : role
End Element : role
Role : admin
Start Element : salary
Currency :EUR
End Element : salary
Salary : 8000
Start Element : bio
End Element : bio
Bio : a & b
End Element : staff
End Element : Company
End Document 

2。XML 中的字符编码和代码

确保我们使用正确的编码来解析 XML 文件。

2.1 对于 XML 文件,最好声明encoding属性。

 <?xml version="1.0" encoding="character-encoding-here"?>
<Company>

</Company> 

例如,下面是一个 UTF 8 编码的 XML 文件。

 <?xml version="1.0" encoding="utf-8"?>
<Company>

</Company> 

2.2 对于 SAX 解析器,我们可以通过XMLReader设置编码。

 SAXParserFactory factory = SAXParserFactory.newInstance();

  try {

      SAXParser saxParser = factory.newSAXParser();

      PrintAllHandlerSax handler = new PrintAllHandlerSax();

      XMLReader xmlReader = saxParser.getXMLReader();
      xmlReader.setContentHandler(handler);

      InputSource source = new InputSource(FILENAME);

      // utf-8
      source.setEncoding(StandardCharsets.UTF_8.displayName());

      // utf-16
      // source.setEncoding(StandardCharsets.UTF_16.displayName());

      // ascii
      // source.setEncoding(StandardCharsets.US_ASCII.displayName());

      xmlReader.parse(source);

  } catch (ParserConfigurationException | SAXException | IOException e) {
      e.printStackTrace();
  } 

3。SAX 常见错误

下面是 SAX XML 解析中的一些常见错误。

3.1 1 字节 UTF-8 序列的无效字节 1

XML 文件包含无效的 UTF-8 字符,读这个

3.2 序言中不允许出现内容

XML 文件在 XML 声明前包含无效文本或 BOM,读

3.3 实体名称必须紧跟在实体引用

中的“&

XML 文件中的&是无效字符,请用&amp;替换或用 CDATA 括起来,例如<![CDATA[a & b]]>

4。下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-xml

$ CD src/main/Java/com/mkyong/XML/sax/

5。参考文献

如何在 Java 中读取 XML 文件—(DOM 解析器)

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

java xml dom parser

本教程将向您展示如何使用 Java 内置的 DOM 解析器来读取 XML 文件。

注意
DOM 解析器在读取大型 XML 文档时速度很慢,并且会消耗大量内存,因为它将所有节点加载到内存中进行遍历和操作。

相反,我们应该考虑 SAX 解析器来读取大尺寸的 XML 文档,SAX 比 DOM 更快并且使用更少的内存。

1。什么是文档对象模型

文档对象模型(DOM)使用节点将 HTML 或 XML 文档表示为树结构。

下面是一个简单的 XML 文档:

 <company>
    <staff id="1001">
        <firstname>yong</firstname>
        <lastname>mook kim</lastname>
        <nickname>mkyong</nickname>
        <salary currency="USD">100000</salary>
    </staff>
</company> 

DOM 常用术语。

  • <company>是根元素。
  • <staff>, <firstname> and all <?>是元素节点。
  • 文本节点是由元素节点包装的值;比如<firstname>yong</firstname>yong就是文本节点。
  • 该属性是元素节点的一部分;例如,<staff id="1001">``idstaff元素的属性。

延伸阅读

2。读取或解析 XML 文件

这个例子向您展示了如何使用 Java 内置的 DOM 解析器 API 来读取或解析 XML 文件。

2.1 查看下面的 XML 文件。

/users/mkyong/staff.xml

 <?xml version="1.0"?>
<company>
    <staff id="1001">
        <firstname>yong</firstname>
        <lastname>mook kim</lastname>
        <nickname>mkyong</nickname>
        <salary currency="USD">100000</salary>
    </staff>
    <staff id="2001">
        <firstname>low</firstname>
        <lastname>yin fong</lastname>
        <nickname>fong fong</nickname>
        <salary currency="INR">200000</salary>
    </staff>
</company> 

下面的 2.2 是一个解析或读取上述 XML 文件的 DOM 解析器示例。

ReadXmlDomParser.java

 package com.mkyong.xml.dom;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
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.File;
import java.io.IOException;
import java.io.InputStream;

public class ReadXmlDomParser {

  private static final String FILENAME = "/users/mkyong/staff.xml";

  public static void main(String[] args) {

      // Instantiate the Factory
      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

      try {

          // optional, but recommended
          // process XML securely, avoid attacks like XML External Entities (XXE)
          dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

          // parse XML file
          DocumentBuilder db = dbf.newDocumentBuilder();

          Document doc = db.parse(new File(FILENAME));

          // optional, but recommended
          // http://stackoverflow.com/questions/13786607/normalization-in-dom-parsing-with-java-how-does-it-work
          doc.getDocumentElement().normalize();

          System.out.println("Root Element :" + doc.getDocumentElement().getNodeName());
          System.out.println("------");

          // get <staff>
          NodeList list = doc.getElementsByTagName("staff");

          for (int temp = 0; temp < list.getLength(); temp++) {

              Node node = list.item(temp);

              if (node.getNodeType() == Node.ELEMENT_NODE) {

                  Element element = (Element) node;

                  // get staff's attribute
                  String id = element.getAttribute("id");

                  // get text
                  String firstname = element.getElementsByTagName("firstname").item(0).getTextContent();
                  String lastname = element.getElementsByTagName("lastname").item(0).getTextContent();
                  String nickname = element.getElementsByTagName("nickname").item(0).getTextContent();

                  NodeList salaryNodeList = element.getElementsByTagName("salary");
                  String salary = salaryNodeList.item(0).getTextContent();

                  // get salary's attribute
                  String currency = salaryNodeList.item(0).getAttributes().getNamedItem("currency").getTextContent();

                  System.out.println("Current Element :" + node.getNodeName());
                  System.out.println("Staff Id : " + id);
                  System.out.println("First Name : " + firstname);
                  System.out.println("Last Name : " + lastname);
                  System.out.println("Nick Name : " + nickname);
                  System.out.printf("Salary [Currency] : %,.2f [%s]%n%n", Float.parseFloat(salary), currency);

              }
          }

      } catch (ParserConfigurationException | SAXException | IOException e) {
          e.printStackTrace();
      }

  }

} 

输出

Terminal

 Root Element :company
------
Current Element :staff
Staff Id : 1001
First Name : yong
Last Name : mook kim
Nick Name : mkyong
Salary [Currency] : 100,000.00 [USD]

Current Element :staff
Staff Id : 2001
First Name : low
Last Name : yin fong
Nick Name : fong fong
Salary [Currency] : 200,000.00 [INR] 

3。读取或解析 XML 文件(Unicode)

在 DOM parser 中,读取普通 XML 文件和 Unicode XML 文件没有区别。

3.1 查看下面包含一些中文字符(Unicode)的 XML 文件。

src/main/resources/staff-unicode.xml

 <?xml version="1.0"?>
<company>
    <staff id="1001">
        <firstname>揚</firstname>
        <lastname>木金</lastname>
        <nickname>mkyong</nickname>
        <salary currency="USD">100000</salary>
    </staff>
    <staff id="2001">
        <firstname>low</firstname>
        <lastname>yin fong</lastname>
        <nickname>fong fong</nickname>
        <salary currency="INR">200000</salary>
    </staff>
</company> 

3.2 下面的示例解析上面的 XML 文件;它逐个循环所有的节点并打印出来。

ReadXmlDomParserLoop.java

 package com.mkyong.xml.dom;

import org.w3c.dom.*;
import org.xml.sax.SAXException;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;

public class ReadXmlDomParserLoop {

  public static void main(String[] args) {

      // Instantiate the Factory
      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

      try (InputStream is = readXmlFileIntoInputStream("staff-unicode.xml")) {

          // parse XML file
          DocumentBuilder db = dbf.newDocumentBuilder();

          // read from a project's resources folder
          Document doc = db.parse(is);

          System.out.println("Root Element :" + doc.getDocumentElement().getNodeName());
          System.out.println("------");

          if (doc.hasChildNodes()) {
              printNote(doc.getChildNodes());
          }

      } catch (ParserConfigurationException | SAXException | IOException e) {
          e.printStackTrace();
      }

  }

  private static void printNote(NodeList nodeList) {

      for (int count = 0; count < nodeList.getLength(); count++) {

          Node tempNode = nodeList.item(count);

          // make sure it's element node.
          if (tempNode.getNodeType() == Node.ELEMENT_NODE) {

              // get node name and value
              System.out.println("\nNode Name =" + tempNode.getNodeName() + " [OPEN]");
              System.out.println("Node Value =" + tempNode.getTextContent());

              if (tempNode.hasAttributes()) {

                  // get attributes names and values
                  NamedNodeMap nodeMap = tempNode.getAttributes();
                  for (int i = 0; i < nodeMap.getLength(); i++) {
                      Node node = nodeMap.item(i);
                      System.out.println("attr name : " + node.getNodeName());
                      System.out.println("attr value : " + node.getNodeValue());
                  }

              }

              if (tempNode.hasChildNodes()) {
                  // loop again if has child nodes
                  printNote(tempNode.getChildNodes());
              }

              System.out.println("Node Name =" + tempNode.getNodeName() + " [CLOSE]");

          }

      }

  }

  // read file from project resource's folder.
  private static InputStream readXmlFileIntoInputStream(final String fileName) {
      return ReadXmlDomParserLoop.class.getClassLoader().getResourceAsStream(fileName);
  }

} 

输出

Terminal

 Root Element :company
------

Node Name =company [OPEN]
Node Value =

        揚
        木金
        mkyong
        100000

        low
        yin fong
        fong fong
        200000

Node Name =staff [OPEN]
Node Value =
        揚
        木金
        mkyong
        100000

attr name : id
attr value : 1001

Node Name =firstname [OPEN]
Node Value =Node Name =firstname [CLOSE]

Node Name =lastname [OPEN]
Node Value =木金
Node Name =lastname [CLOSE]

Node Name =nickname [OPEN]
Node Value =mkyong
Node Name =nickname [CLOSE]

Node Name =salary [OPEN]
Node Value =100000
attr name : currency
attr value : USD
Node Name =salary [CLOSE]
Node Name =staff [CLOSE]

Node Name =staff [OPEN]
Node Value =
        low
        yin fong
        fong fong
        200000

attr name : id
attr value : 2001

Node Name =firstname [OPEN]
Node Value =low
Node Name =firstname [CLOSE]

Node Name =lastname [OPEN]
Node Value =yin fong
Node Name =lastname [CLOSE]

Node Name =nickname [OPEN]
Node Value =fong fong
Node Name =nickname [CLOSE]

Node Name =salary [OPEN]
Node Value =200000
attr name : currency
attr value : INR
Node Name =salary [CLOSE]
Node Name =staff [CLOSE]
Node Name =company [CLOSE] 

4。解析 Alexa API XML 响应

这个例子展示了如何使用 DOM 解析器解析来自 Alexa 的 API 的 XML 响应。

4.1 向下面的 Alexa API 发送请求。

Terminal

 https://data.alexa.com/data?cli=10&url;=mkyong.com 

4.2 Alexa API 将返回以下 XML 响应。Alexa 排名在POPULARITY元素内,即TEXT属性。

 <!--  Need more Alexa data?  Find our APIs here: https://aws.amazon.com/alexa/  -->
<ALEXA VER="0.9" URL="mkyong.com/" HOME="0" AID="=" IDN="mkyong.com/">
  <SD>
    <POPULARITY URL="mkyong.com/" TEXT="20162" SOURCE="panel"/>
    <REACH RANK="14430"/>
    <RANK DELTA="+947"/>
    <COUNTRY CODE="IN" NAME="India" RANK="4951"/>
  </SD>
</ALEXA> 

4.3 我们使用一个 DOM 解析器直接选择POPULARITY元素并打印出TEXT属性的值。

ReadXmlAlexaApi.java

 package com.mkyong.xml.dom;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

public class ReadXmlAlexaApi {

    private static final String ALEXA_API = "http://data.alexa.com/data?cli=10&url=";
    private final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

    public static void main(String[] args) {

        ReadXmlAlexaApi obj = new ReadXmlAlexaApi();
        int alexaRanking = obj.getAlexaRanking("mkyong.com");

        System.out.println("Ranking: " + alexaRanking);

    }

    public int getAlexaRanking(String domain) {

        int result = 0;

        String url = ALEXA_API + domain;

        try {

            URLConnection conn = new URL(url).openConnection();

            try (InputStream is = conn.getInputStream()) {

                // unknown XML better turn on this
                dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

                DocumentBuilder dBuilder = dbf.newDocumentBuilder();

                Document doc = dBuilder.parse(is);

                Element element = doc.getDocumentElement();

                // find this tag "POPULARITY"
                NodeList nodeList = element.getElementsByTagName("POPULARITY");
                if (nodeList.getLength() > 0) {

                    Element elementAttribute = (Element) nodeList.item(0);
                    String ranking = elementAttribute.getAttribute("TEXT");
                    if (!"".equals(ranking)) {
                        result = Integer.parseInt(ranking);
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            throw new IllegalArgumentException("Invalid request for domain : " + domain);
        }

        return result;
    }

} 

域名mkyong.com排名20162

Terminal

 Ranking: 20162 

注意
更多 DOM 解析器示例—Oracle—将 XML 数据读入 DOM

5。下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-xml

$ CD src/main/Java/com/mkyong/XML/DOM/

6。参考文献

如何在 Java 中读取 XML 文件—(JDOM 解析器)

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-read-xml-file-in-java-jdom-example/

JDOM 是构建在 DOM 和 SAX 之上的基于 Java 的开源 XML 解析器框架,也是 XML 文档的文档对象模型(DOM) 内存表示。

JDOM 通过提供更简单的 API 和标准的基于 Java 的集合接口,使得 XML 文档的导航更加容易。如果您不介意下载一个小库来解析 XML 文件,JDOM APIs 很容易使用。

1。下载 JDOM 库

JDOM 不是 Java 内置 API 的一部分,我们需要下载 JDOM 库。

Maven for JDOM。

pom.xml

 <dependency>
      <groupId>org.jdom</groupId>
      <artifactId>jdom2</artifactId>
      <version>2.0.6</version>
  </dependency> 

2。读取或解析 XML 文件(JDOM)

这个例子展示了如何使用 JDOM 来解析 XML 文件。

2.1 一个 XML 文件。

src/main/resources/staff.xml

 <?xml version="1.0" encoding="utf-8"?>
<Company>
    <staff id="1001">
        <name>mkyong</name>
        <role>support</role>
        <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.2 解析并打印出所有 XML 元素和节点的 JDOM 示例。

ReadXmlJDomParser.java

 package com.mkyong.xml.jdom;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;

import java.io.File;
import java.io.IOException;
import java.util.List;

public class ReadXmlJDomParser {

  private static final String FILENAME = "src/main/resources/staff.xml";

  public static void main(String[] args) {

      try {

          SAXBuilder sax = new SAXBuilder();
          // XML is a local file
          Document doc = sax.build(new File(FILENAME));

          Element rootNode = doc.getRootElement();
          List<Element> list = rootNode.getChildren("staff");

          for (Element target : list) {

              String id = target.getAttributeValue("id");
              String name = target.getChildText("name");
              String role = target.getChildText("role");
              String salary = target.getChildText("salary");
              String currency = "";
              if (salary != null && salary.length() > 1) {
                  // access attribute
                  currency = target.getChild("salary").getAttributeValue("currency");
              }
              String bio = target.getChildText("bio");

              System.out.printf("Staff id : %s%n", id);
              System.out.printf("Name : %s%n", name);
              System.out.printf("Role : %s%n", role);
              System.out.printf("Salary [Currency] : %,.2f [%s]%n", Float.parseFloat(salary), currency);
              System.out.printf("Bio : %s%n%n", bio);

          }

      } catch (IOException | JDOMException e) {
          e.printStackTrace();
      }

  }
} 

输出

Terminal

 Staff id : 1001
Name : mkyong
Role : support
Salary [Currency] : 5,000.00 [USD]
Bio : HTML tag <code>testing</code>

Staff id : 1002
Name : yflow
Role : admin
Salary [Currency] : 8,000.00 [EUR]
Bio : a & b 

3。读取或解析远程 XML 文件(JDOM)

这个示例使用 JDOM 解析器来读取或解析远程或基于网站的 XML 文件。

3.1 访问 Alexa API https://data.alexa.com/data?cli=10&url=mkyong.com,它会返回下面的 XML 文件。

 <ALEXA VER="0.9" URL="mkyong.com/" HOME="0" AID="=" IDN="mkyong.com/">
  <SD>
    <POPULARITY URL="mkyong.com/" TEXT="20152" SOURCE="panel"/>
    <REACH RANK="14434"/>
    <RANK DELTA="+728"/>
    <COUNTRY CODE="IN" NAME="India" RANK="5322"/>
  </SD>
</ALEXA> 

3.2 JDOM 获取网站 Alexa 排名的例子。

ReadXmlAlexaApiJDomParser.java

 package com.mkyong.xml.jdom;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;

import java.io.IOException;
import java.net.URL;
import java.util.List;

public class ReadXmlAlexaApiJDomParser {

    private static final String REMOTE_URL
        = "https://data.alexa.com/data?cli=10&url=mkyong.com";

    public static void main(String[] args) {

        try {

            SAXBuilder sax = new SAXBuilder();
            // XML is in a web-based location
            Document doc = sax.build(new URL(REMOTE_URL));

            Element rootNode = doc.getRootElement();
            List<Element> list = rootNode.getChildren("SD");

            for (Element target : list) {

                Element popularity = target.getChild("POPULARITY");

                String url = popularity.getAttributeValue("URL");
                String rank = popularity.getAttributeValue("TEXT");

                System.out.printf("URL : %s%n", url);
                System.out.printf("Alexa Rank : %s%n", rank);

            }

        } catch (IOException | JDOMException e) {
            e.printStackTrace();
        }

    }
} 

输出

Terminal

 URL : mkyong.com/
Alexa Rank : 20152 

4。包含 XML 的字符串

这个例子展示了 JDOM 如何解析包含 XML 的String

ReadXmlStringJDomParser.java

 package com.mkyong.xml.jdom;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;

import java.io.IOException;
import java.io.StringReader;

public class ReadXmlStringJDomParser {

    public static void main(String[] args) {

        String XML = "<root><url>mkyong</url></root>";

        try {

            SAXBuilder sax = new SAXBuilder();
            // String that contains XML
            Document doc = sax.build(new StringReader(XML));

            Element rootNode = doc.getRootElement();
            System.out.println(rootNode.getChildText("url"));

        } catch (IOException | JDOMException e) {
            e.printStackTrace();
        }

    }
} 

输出

Terminal

 mkyong 


更多 JDOM2 示例——JDOM 2 入门

5。下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-xml

$ CD src/main/Java/com/mkyong/XML/JDOM/

6。参考文献

如何在 Java 中读取 XML 文件(SAX 解析器)

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-read-xml-file-in-java-sax-parser/

本教程将向您展示如何使用 Java 内置的 SAX 解析器来读取和解析 XML 文件。

1。什么是 XML 的简单 API(SAX)

1.1XML 的简单 API(SAX)是一个推送 API,一个观察者模式,事件驱动,顺序地串行访问 XML 文件元素。这个 SAX 解析器从头到尾读取 XML 文件,在遇到一个元素时调用一个方法,或者在找到特定的文本或属性时调用不同的方法。

SAX 快速高效,比 DOM 需要更少的内存,因为 SAX 不像 DOM 那样创建 XML 数据的内部表示(树结构)。

注意
SAX 解析器比 DOM 解析器更快,使用的内存更少。SAX 适合顺序读取 XML 元素;DOM 适合于 XML 操作,比如创建、修改或删除 XML 元素。

1.2 一些常见的 SAX 事件:

  • startDocument()endDocument()–在 XML 文档的开头和结尾调用的方法。
  • startElement()endElement()–在 XML 元素的开头和结尾调用的方法。
  • characters()–用 XML 元素开始和结束之间的文本内容调用的方法。

1.3 下面是一个简单的 XML 文件。

 <name>mkyong</name> 

SAX 解析器读取上面的 XML 文件,并依次调用以下事件或方法:

  1. startDocument()
  2. startElement()<name>
  3. characters()mkyong
  4. endElement()</name>
  5. endDocument()

2。读取或解析 XML 文件(SAX)

这个例子向您展示了如何使用 Java 内置的 SAX 解析器 API 来读取或解析 XML 文件。

下面是一个 XML 文件。

src/main/resources/staff.xml

 <?xml version="1.0" encoding="utf-8"?>
<Company>
    <staff id="1001">
        <name>mkyong</name>
        <role>support</role>
        <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> 

P.S 在 XML 文件中,对于像<或者&这样的特殊字符,我们需要用CDATA将其包裹起来。

2.2 创建一个类来扩展org.xml.sax.helpers.DefaultHandler,并覆盖startElementendElementcharacters方法来打印所有的 XML 元素、属性、注释和文本。

PrintAllHandlerSax.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 PrintAllHandlerSax extends DefaultHandler {

  private StringBuilder currentValue = new StringBuilder();

  @Override
  public void startDocument() {
      System.out.println("Start Document");
  }

  @Override
  public void endDocument() {
      System.out.println("End Document");
  }

  @Override
  public void startElement(
          String uri,
          String localName,
          String qName,
          Attributes attributes) {

      // reset the tag value
      currentValue.setLength(0);

      System.out.printf("Start Element : %s%n", qName);

      if (qName.equalsIgnoreCase("staff")) {
          // get tag's attribute by name
          String id = attributes.getValue("id");
          System.out.printf("Staff id : %s%n", id);
      }

      if (qName.equalsIgnoreCase("salary")) {
          // get tag's attribute by index, 0 = first attribute
          String currency = attributes.getValue(0);
          System.out.printf("Currency :%s%n", currency);
      }

  }

  @Override
  public void endElement(String uri,
                         String localName,
                         String qName) {

      System.out.printf("End Element : %s%n", qName);

      if (qName.equalsIgnoreCase("name")) {
          System.out.printf("Name : %s%n", currentValue.toString());
      }

      if (qName.equalsIgnoreCase("role")) {
          System.out.printf("Role : %s%n", currentValue.toString());
      }

      if (qName.equalsIgnoreCase("salary")) {
          System.out.printf("Salary : %s%n", currentValue.toString());
      }

      if (qName.equalsIgnoreCase("bio")) {
          System.out.printf("Bio : %s%n", currentValue.toString());
      }

  }

  // http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html#characters%28char%5B%5D,%20int,%20int%29
  // SAX parsers may return all contiguous character data in a single chunk,
  // or they may split it into several chunks
  @Override
  public void characters(char ch[], int start, int length) {

      // The characters() method can be called multiple times for a single text node.
      // Some values may missing if assign to a new string

      // avoid doing this
      // value = new String(ch, start, length);

      // better append it, works for single or multiple calls
      currentValue.append(ch, start, length);

  }

} 

2.3 SAXParser解析 XML 文件。

ReadXmlSaxParser.java

 package com.mkyong.xml.sax;

import com.mkyong.xml.sax.handler.PrintAllHandlerSax;
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();

            PrintAllHandlerSax handler = new PrintAllHandlerSax();
            saxParser.parse(FILENAME, handler);

        } catch (ParserConfigurationException | SAXException | IOException e) {
            e.printStackTrace();
        }

    }

} 

输出

Terminal

 Start Document
Start Element : Company
Start Element : staff
Staff id : 1001
Start Element : name
End Element : name
Name : mkyong
Start Element : role
End Element : role
Role : support
Start Element : salary
Currency :USD
End Element : salary
Salary : 5000
Start Element : bio
End Element : bio
Bio : HTML tag <code>testing</code>
End Element : staff
Start Element : staff
Staff id : 1002
Start Element : name
End Element : name
Name : yflow
Start Element : role
End Element : role
Role : admin
Start Element : salary
Currency :EUR
End Element : salary
Salary : 8000
Start Element : bio
End Element : bio
Bio : a & b
End Element : staff
End Element : Company
End Document 

3。将 XML 文件转换成对象

这个例子解析一个 XML 文件并把它转换成一个对象的List。它有效,但不推荐,试试 JAXB

3.1 检查同一个 XML 文件。

src/main/resources/staff.xml

 <?xml version="1.0" encoding="utf-8"?>
<Company>
    <staff id="1001">
        <name>mkyong</name>
        <role>support</role>
        <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> 

3.2 我们想将上面的 XML 文件转换成下面的Staff对象。

Staff.java

 package com.mkyong.xml.sax.model;

import java.math.BigDecimal;

public class Staff {

  private Long id;
  private String name;
  private String role;
  private BigDecimal salary;
  private String Currency;
  private String bio;

  //... getters, setters...toString
} 

3.3 下面的类将完成 XML 到对象的转换。

MapStaffObjectHandlerSax.java

 package com.mkyong.xml.sax.handler;

import com.mkyong.xml.sax.model.Staff;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

public class MapStaffObjectHandlerSax extends DefaultHandler {

    private StringBuilder currentValue = new StringBuilder();
    List<Staff> result;
    Staff currentStaff;

    public List<Staff> getResult() {
        return result;
    }

    @Override
    public void startDocument() {
        result = new ArrayList<>();
    }

    @Override
    public void startElement(
            String uri,
            String localName,
            String qName,
            Attributes attributes) {

        // reset the tag value
        currentValue.setLength(0);

        // start of loop
        if (qName.equalsIgnoreCase("staff")) {

            // new staff
            currentStaff = new Staff();

            // staff id
            String id = attributes.getValue("id");
            currentStaff.setId(Long.valueOf(id));
        }

        if (qName.equalsIgnoreCase("salary")) {
            // salary currency
            String currency = attributes.getValue("currency");
            currentStaff.setCurrency(currency);
        }

    }

    public void endElement(String uri,
                           String localName,
                           String qName) {

        if (qName.equalsIgnoreCase("name")) {
            currentStaff.setName(currentValue.toString());
        }

        if (qName.equalsIgnoreCase("role")) {
            currentStaff.setRole(currentValue.toString());
        }

        if (qName.equalsIgnoreCase("salary")) {
            currentStaff.setSalary(new BigDecimal(currentValue.toString()));
        }

        if (qName.equalsIgnoreCase("bio")) {
            currentStaff.setBio(currentValue.toString());
        }

        // end of loop
        if (qName.equalsIgnoreCase("staff")) {
            result.add(currentStaff);
        }

    }

    public void characters(char ch[], int start, int length) {
        currentValue.append(ch, start, length);

    }

} 

3.4 运行它。

ReadXmlSaxParser2.java

 package com.mkyong.xml.sax;

import com.mkyong.xml.sax.handler.MapStaffObjectHandlerSax;
import com.mkyong.xml.sax.model.Staff;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class ReadXmlSaxParser2 {

    public static void main(String[] args) {

        SAXParserFactory factory = SAXParserFactory.newInstance();

        try (InputStream is = getXMLFileAsStream()) {

            SAXParser saxParser = factory.newSAXParser();

            // parse XML and map to object, it works, but not recommend, try JAXB
            MapStaffObjectHandlerSax handler = new MapStaffObjectHandlerSax();

            saxParser.parse(is, handler);

            // print all
            List<Staff> result = handler.getResult();
            result.forEach(System.out::println);

        } catch (ParserConfigurationException | SAXException | IOException e) {
            e.printStackTrace();
        }

    }

    // get XML file from resources folder.
    private static InputStream getXMLFileAsStream() {
        return ReadXmlSaxParser2.class.getClassLoader().getResourceAsStream("staff.xml");
    }

} 

输出

Terminal

 Staff{id=1001, name='揚木金', role='support', salary=5000, Currency='USD', bio='HTML tag <code>testing</code>'}
Staff{id=1002, name='yflow', role='admin', salary=8000, Currency='EUR', bio='a & b'} 

4。SAX 错误处理程序

这个例子展示了如何为 SAX 解析器注册一个定制的错误处理程序。

4.1 创建一个类并扩展org.xml.sax.ErrorHandler。阅读代码进行自我解释。它只是包装了原始错误消息。

CustomErrorHandlerSax.java

 package com.mkyong.xml.sax.handler;

import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import java.io.PrintStream;

public class CustomErrorHandlerSax implements ErrorHandler {

    private PrintStream out;

    public CustomErrorHandlerSax(PrintStream out) {
        this.out = out;
    }

    private String getParseExceptionInfo(SAXParseException spe) {
        String systemId = spe.getSystemId();

        if (systemId == null) {
            systemId = "null";
        }

        String info = "URI=" + systemId + " Line="
                + spe.getLineNumber() + ": " + spe.getMessage();

        return info;
    }

    public void warning(SAXParseException spe) throws SAXException {
        out.println("Warning: " + getParseExceptionInfo(spe));
    }

    public void error(SAXParseException spe) throws SAXException {
        String message = "Error: " + getParseExceptionInfo(spe);
        throw new SAXException(message);
    }

    public void fatalError(SAXParseException spe) throws SAXException {
        String message = "Fatal Error: " + getParseExceptionInfo(spe);
        throw new SAXException(message);
    }

} 

4.2 我们使用saxParser.getXMLReader()来获得org.xml.sax.XMLReader,它提供了更多配置 SAX 解析器的选项。

ReadXmlSaxParser3.java

 package com.mkyong.xml.sax;

import com.mkyong.xml.sax.handler.CustomErrorHandlerSax;
import com.mkyong.xml.sax.handler.MapStaffObjectHandlerSax;
import com.mkyong.xml.sax.model.Staff;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class ReadXmlSaxParser3 {

  public static void main(String[] args) {

      SAXParserFactory factory = SAXParserFactory.newInstance();

      try (InputStream is = getXMLFileAsStream()) {

          SAXParser saxParser = factory.newSAXParser();

          // parse XML and map to object, it works, but not recommend, try JAXB
          MapStaffObjectHandlerSax handler = new MapStaffObjectHandlerSax();

          // try XMLReader
          //saxParser.parse(is, handler);

          // more options for configuration
          XMLReader xmlReader = saxParser.getXMLReader();

          // set our custom error handler
          xmlReader.setErrorHandler(new CustomErrorHandlerSax(System.err));

          xmlReader.setContentHandler(handler);

          InputSource source = new InputSource(is);

          xmlReader.parse(source);

          // print all
          List<Staff> result = handler.getResult();
          result.forEach(System.out::println);

      } catch (ParserConfigurationException | SAXException | IOException e) {
          e.printStackTrace();
      }

  }

  // get XML file from resources folder.
  private static InputStream getXMLFileAsStream() {
      return ReadXmlSaxParser2.class.getClassLoader().getResourceAsStream("staff.xml");
  }

} 

4.3 更新staff.xml,去掉bio元素中的CDATA,放一个&,SAX 解析器会报错。

src/main/resources/staff.xml

 <?xml version="1.0" encoding="utf-8"?>
<Company>
    <staff id="1001">
        <name>mkyong</name>
        <role>support</role>
        <salary currency="USD">5000</salary>
        <!-- for special characters like < &, need CDATA -->
        <bio>&</bio>
    </staff>
</Company> 

4.4 用上面的自定义错误处理程序运行它。

 xmlReader.setErrorHandler(new CustomErrorHandlerSax(System.err)); 

输出

Terminal

 org.xml.sax.SAXException: Fatal Error: URI=null Line=8: The entity name must immediately follow the '&' in the entity reference.
at com.mkyong.xml.sax.handler.CustomErrorHandlerSax.fatalError(CustomErrorHandlerSax.java:41)
at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:181)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:400)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:327)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(XMLScanner.java:1471)
//... 

4.5 在没有自定义错误处理程序的情况下运行它。

 // xmlReader.setErrorHandler(new CustomErrorHandlerSax(System.err)); 

输出

Terminal

 [Fatal Error] :8:15: The entity name must immediately follow the '&' in the entity reference.
org.xml.sax.SAXParseException; lineNumber: 8; columnNumber: 15; The entity name must immediately follow the '&' in the entity reference.
	at java.xml/com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1243)
	at java.xml/com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:635)
	at com.mkyong.xml.sax.ReadXmlSaxParser2.main(ReadXmlSaxParser2.java:44) 

5。SAX 和 Unicode

对于包含 Unicode 字符的 XML 文件,默认情况下,SAX 可以遵循 XML 编码(默认的 UTF-8)并正确解析内容。

5.1 我们可以在 XML 文件的顶部定义编码,encoding="encoding-code";例如,下面是一个使用UTF-8编码的 XML 文件。

 <?xml version="1.0" encoding="utf-8"?>
<Company>
    <staff id="1001">
        <name>揚木金</name>
        <role>support</role>
        <salary currency="USD">5000</salary>
        <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> 

5.2 或者,我们可以在InputSource中定义一个指定的编码。

 XMLReader xmlReader = saxParser.getXMLReader();
  xmlReader.setContentHandler(handler);

  InputSource source = new InputSource(is);

  // set encoding
  source.setEncoding(StandardCharsets.UTF_8.toString());

  //source.setEncoding(StandardCharsets.UTF_16.toString());

  xmlReader.parse(source); 

注意
更多 SAX 解析器示例—Oracle—简单 XML API(SAX)

6。下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-xml

$ CD src/main/Java/com/mkyong/XML/sax/

7。参考文献

如何在 Java 中读取 XML 文件(StAX 解析器)

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-read-xml-file-in-java-stax-parser/

本教程展示了如何使用 Streaming API for XML (StAX) 解析器来读取或解析 XML 文档。

目录


P . S XML 的流 API(StAX)API 从 Java 1.6 开始提供,内置 JDK XML 库。

下面所有的例子都是用 Java 11 测试的。

1。StAX

是什么

StAX 代表Streaming API for XML (StAX),一个处理 XML 文档的pull API

有两种处理 XML 文档的编程模型,流式和文档对象模型(DOM)。对于 DOM 模型,我们可以使用 DOM 解析器;对于流式模型,我们可以使用 SAX 解析器或者 StAX 解析器。

1.1 SAX 和 StAX 的区别?

Simple API for XML (SAX)是一个push API;这个 SAX 解析器不断地向客户机发送(推送)XML 数据。在 SAX 中,客户机无法控制何时接收 XML 数据。

例如,我们注册了一个定制的DefaultHandler实现来处理 SAX 解析器发送的 XML 数据。阅读完整的 SAX 示例

 // SAX
  SAXParser saxParser = factory.newSAXParser();

  // DefaultHandler implementation
  PrintAllHandlerSax handler = new PrintAllHandlerSax();

  saxParser.parse(FILENAME, handler); 

Streaming API for XML (StAX)是一个pull API;客户机调用 StAX 解析器库的方法,手动一个接一个地获取(拉取)XML 数据。在 StAX 中,控制何时获取(拉取)XML 数据的客户机。

 // StAX Iterator API examples
  // next event
  XMLEvent event = xmlEventReader.nextEvent();

  // moves to next event
  event = xmlEventReader.nextEvent();

  // moves to next event
  event = xmlEventReader.nextEvent(); 

延伸阅读

2。StAX 游标 API 和迭代器 API

StAX 包含两个 API 集:一个游标 API 和一个迭代器 API。

2.1 StAX 游标 API

StAX Cursor API 包含两个主要接口XMLStreamReaderXMLStreamWriterXMLStreamReader.getEventType()将返回一个int,我们需要手动映射事件类型。

 // StAX Cursor API
  XMLStreamReader reader = xmlInputFactory.createXMLStreamReader(
      new FileInputStream(path.toFile()));

  // this is int! we need to map the eventType manually
  int eventType = reader.getEventType();

  while (reader.hasNext()) {

      eventType = reader.next();

      if (eventType == XMLEvent.START_ELEMENT) {
      }
      //...
  } 

2.2 StAX 迭代器 API

StAX 迭代器 API 包含两个主要接口XMLEventReaderXMLEventWriter,我们使用 XMLEvent

 // StAX Iterator API
  XMLEventReader reader = xmlInputFactory.createXMLEventReader(
      new FileInputStream(path.toFile()));

  // event iterator
  while (reader.hasNext()) {

      XMLEvent event = reader.nextEvent();

      if (event.isStartElement()) {
      }
      //...
  } 

2.3 哪一个?游标还是迭代器 API?

  • 与迭代器 API 相比,游标 API 的代码更小,效率更高,性能也更好。适合高性能应用程序或移动应用程序。
  • 迭代器 API 提供了 XML 事件,这种事件更加灵活、可扩展、易于编码,适合企业应用程序。

延伸阅读

3。一个 XML 文件

下面是一个 XML 文档,稍后我们使用 StAX 解析器读取 XML 数据并打印出来。

src/main/resources/staff.xml

 <?xml version="1.0" encoding="utf-8"?>
<Company>
    <staff id="1001">
        <name>mkyong</name>
        <role>support</role>
        <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> 

4。StAX 游标 API 读取 XML 文件

以下示例使用 StAX Cursor API 读取或解析上述 XML 文件,以获取 XML 元素、属性、CDATA 等。

ReadXmlStAXCursorParser.java

 package com.mkyong.xml.stax;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.events.XMLEvent;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.nio.file.Path;
import java.nio.file.Paths;

public class ReadXmlStAXCursorParser {

    private static final String FILENAME = "src/main/resources/staff.xml";

    public static void main(String[] args) {

        try {

            printXmlByXmlCursorReader(Paths.get(FILENAME));

        } catch (FileNotFoundException | XMLStreamException e) {
            e.printStackTrace();
        }

    }

    private static void printXmlByXmlCursorReader(Path path)
            throws FileNotFoundException, XMLStreamException {

        XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
        XMLStreamReader reader = xmlInputFactory.createXMLStreamReader(
                new FileInputStream(path.toFile()));

        int eventType = reader.getEventType();
        System.out.println(eventType);   // 7, START_DOCUMENT
        System.out.println(reader);      // xerces

        while (reader.hasNext()) {

            eventType = reader.next();

            if (eventType == XMLEvent.START_ELEMENT) {

                switch (reader.getName().getLocalPart()) {

                    case "staff":
                        String id = reader.getAttributeValue(null, "id");
                        System.out.printf("Staff id : %s%n", id);
                        break;

                    case "name":
                        eventType = reader.next();
                        if (eventType == XMLEvent.CHARACTERS) {
                            System.out.printf("Name : %s%n", reader.getText());
                        }
                        break;

                    case "role":
                        eventType = reader.next();
                        if (eventType == XMLEvent.CHARACTERS) {
                            System.out.printf("Role : %s%n", reader.getText());
                        }
                        break;

                    case "salary":
                        String currency = reader.getAttributeValue(null, "currency");
                        eventType = reader.next();
                        if (eventType == XMLEvent.CHARACTERS) {
                            String salary = reader.getText();
                            System.out.printf("Salary [Currency] : %,.2f [%s]%n",
                              Float.parseFloat(salary), currency);
                        }
                        break;

                    case "bio":
                        eventType = reader.next();
                        if (eventType == XMLEvent.CHARACTERS) {
                            System.out.printf("Bio : %s%n", reader.getText());
                        }
                        break;
                }

            }

            if (eventType == XMLEvent.END_ELEMENT) {
                // if </staff>
                if (reader.getName().getLocalPart().equals("staff")) {
                    System.out.printf("%n%s%n%n", "---");
                }
            }

        }

    }

} 

输出

Terminal

 7
com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl@18be83e4

Staff id : 1001
Name : mkyong
Role : support
Salary [Currency] : 5,000.00 [USD]
Bio : HTML tag <code>testing</code>

---

Staff id : 1002
Name : yflow
Role : admin
Salary [Currency] : 8,000.00 [EUR]
Bio : a & b

--- 

下面是光标 API 事件类型及其int的代码助手

Cursor API event type

5。StAX 迭代器 API 读取 XML 文件

下面的例子使用 StAX 迭代器 API 来读取或解析上面的 XML 文件,以获得 XML 元素、属性、CDATA 等。

ReadXmlStAXEventParser.java

 package com.mkyong.xml.stax;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.nio.file.Path;
import java.nio.file.Paths;

public class ReadXmlStAXEventParser {

    private static final String FILENAME = "src/main/resources/staff.xml";

    public static void main(String[] args) {

        try {

            printXmlByXmlEventReader(Paths.get(FILENAME));

        } catch (FileNotFoundException | XMLStreamException e) {
            e.printStackTrace();
        }

    }

    private static void printXmlByXmlEventReader(Path path)
            throws FileNotFoundException, XMLStreamException {

        XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
        XMLEventReader reader = xmlInputFactory.createXMLEventReader(
                new FileInputStream(path.toFile()));

        // event iterator
        while (reader.hasNext()) {

            XMLEvent event = reader.nextEvent();

            if (event.isStartElement()) {

                StartElement element = event.asStartElement();

                switch (element.getName().getLocalPart()) {
                    // if <staff>
                    case "staff":
                        // id='1001'
                        Attribute id = element.getAttributeByName(new QName("id"));
                        System.out.printf("Staff id : %s%n", id.getValue());
                        break;
                    case "name":
                        // throws StartElementEvent cannot be cast to class javax.xml.stream.events.Characters
                        // element.asCharacters().getData()

                        // this is still '<name>' tag, need move to next event for the character data
                        event = reader.nextEvent();
                        if (event.isCharacters()) {
                            System.out.printf("Name : %s%n", event.asCharacters().getData());
                        }
                        break;
                    case "role":
                        event = reader.nextEvent();
                        if (event.isCharacters()) {
                            System.out.printf("Role : %s%n", event.asCharacters().getData());
                        }
                        break;
                    case "salary":
                        // currency='USD'
                        Attribute currency = element.getAttributeByName(new QName("currency"));
                        event = reader.nextEvent();
                        if (event.isCharacters()) {
                            String salary = event.asCharacters().getData();
                            System.out.printf("Salary [Currency] : %,.2f [%s]%n",
                              Float.parseFloat(salary), currency);
                        }
                        break;
                    case "bio":
                        event = reader.nextEvent();
                        if (event.isCharacters()) {
                            // CDATA, no problem.
                            System.out.printf("Bio : %s%n", event.asCharacters().getData());
                        }
                        break;
                }
            }

            if (event.isEndElement()) {
                EndElement endElement = event.asEndElement();
                // if </staff>
                if (endElement.getName().getLocalPart().equals("staff")) {
                    System.out.printf("%n%s%n%n", "---");
                }
            }

        }

    }

} 

输出

Terminal

 Staff id : 1001
Name : mkyong
Role : support
Salary [Currency] : 5,000.00 [currency='USD']
Bio : HTML tag <code>testing</code>

---

Staff id : 1002
Name : yflow
Role : admin
Salary [Currency] : 8,000.00 [currency='EUR']
Bio : a & b

--- 

6。将 XML 转换成 Java 对象?

是的,我们可以使用 StAX API 将 XML 转换成 Java 对象。对于上面的例子,我们已经可以获得 XML 数据,创建一个类似于Staff.java的 POJO 并手动设置值。

Jakarta XML Binding (JAXB) 是一个推荐的库,用于将 XML 与 Java 对象相互转换。

7。下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-xml

$ CD src/main/Java/com/mkyong/XML/StAX/

8。参考文献

如何在 jQuery 中刷新页面?

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jquery/how-to-refresh-a-page-in-jquery/

要用 jQuery 刷新或重新加载页面,可以使用"location . reload();”命令。

 <html>
<head>
<title>Refresh a page in jQuery</title>

<script type="text/javascript" src="jquery-1.3.2.min.js"></script>

</head>

<body>

<button id="PageRefresh">Refresh a Page in jQuery</button>

<script type="text/javascript">

	$('#PageRefresh').click(function() {

    	      location.reload();

	});

</script>

</body>
</html> 

Tags : jquery refresh page

如何删除 Struts 2 中的 action 后缀扩展

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/struts2/how-to-remove-the-action-suffix-extension-in-struts-2/

Download It – Struts2-Custom-Extension-Example.zip

在 Struts 2 中,所有的 action 类都有一个默认的后缀。动作扩展。举个例子,

 <struts>
  <package name="default" namespace="/" extends="struts-default">
	<action name="SayStruts2">
		<result>pages/printStruts2.jsp</result>
	</action>
  </package>
</struts> 

要访问“SayStruts2”操作类,请使用以下 URL:

 Action URL : http://localhost:8080/Struts2Example/SayStruts2.action 

配置操作扩展

Struts 2 允许轻松配置动作扩展,要更改它,只需声明一个常量" struts.action.extension 值:

1.html 扩展

将操作类更改为。html 扩展。

 <struts>

  <constant name="struts.action.extension" value="html"/> 

  <package name="default" namespace="/" extends="struts-default">
	<action name="SayStruts2">
		<result>pages/printStruts2.jsp</result>
	</action>
  </package>

</struts> 

现在,您可以通过以下方式访问“SayStruts2”操作类

 Action URL : http://localhost:8080/Struts2Example/SayStruts2.html 

2.没有扩展

将操作类更改为空扩展。

 <struts>

  <constant name="struts.action.extension" value=""/> 

  <package name="default" namespace="/" extends="struts-default">
	<action name="SayStruts2">
		<result>pages/printStruts2.jsp</result>
	</action>
  </package>

</struts> 

现在,您可以通过以下方式访问“SayStruts2”操作类

 Action URL : http://localhost:8080/Struts2Example/SayStruts2 

extension struts2

如何在 Java 中重命名或移动文件

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

在 Java 中,我们可以使用 NIO Files.move(source, target)来重命名或移动文件。

 import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

  //...

  Path source = Paths.get("/home/mkyong/newfolder/test1.txt");
  Path target = Paths.get("/home/mkyong/newfolder/test2.txt");

  try{

    Files.move(source, target);

  } catch (IOException e) {
    e.printStackTrace();
  } 

1.重命名同一目录中的文件。

1.1 此示例重命名同一目录中的一个文件,保留相同的文件名。

  • 从此处重命名文件/home/mkyong/hello.txt
  • 到此/home/mkyong/newName.txt
 Path source = Paths.get("/home/mkyong/hello.txt");

  try{

    // rename a file in the same directory
    Files.move(source, source.resolveSibling("newName.txt"));

  } catch (IOException e) {
    e.printStackTrace();
  } 

1.2 如果目标文件存在,Files.move抛出FileAlreadyExistsException

 java.nio.file.FileAlreadyExistsException: /home/mkyong/newName.txt
	at java.base/sun.nio.fs.UnixCopyFile.move(UnixCopyFile.java:450)
	at java.base/sun.nio.fs.UnixFileSystemProvider.move(UnixFileSystemProvider.java:267)
	at java.base/java.nio.file.Files.move(Files.java:1421)
	at com.mkyong.io.file.FileRename.main(FileRename.java:26) 

1.3 如果指定了REPLACE_EXISTING选项,并且目标文件存在,则Files.move将替换它。

 import java.nio.file.StandardCopyOption;

  Files.move(source, source.resolveSibling("newName.txt"),
              StandardCopyOption.REPLACE_EXISTING); 

2.将文件移动到新目录。

2.1 本示例将一个文件移动到一个新目录,并保留相同的文件名。如果目标文件存在,替换它。

  • 从此处移动文件/home/mkyong/hello.txt
  • 到此/home/mkyong/newfolder/hello.txt
 Path source = Paths.get("/home/mkyong/hello.txt");

  Path newDir = Paths.get("/home/mkyong/newfolder/");

  //create the target directories, if directory exits, no effect
  Files.createDirectories(newDir);

  Files.move(source, newDir.resolve(source.getFileName()),
              StandardCopyOption.REPLACE_EXISTING); 

2.2 如果目标目录不存在,Files.move抛出NoSuchFileException

 java.nio.file.NoSuchFileException: /home/mkyong/hello.txt -> /home/mkyong/newfolder/hello2.txt
  	at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:92)
  	at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
  	at java.base/sun.nio.fs.UnixCopyFile.move(UnixCopyFile.java:478)
  	at java.base/sun.nio.fs.UnixFileSystemProvider.move(UnixFileSystemProvider.java:267)
  	at java.base/java.nio.file.Files.move(Files.java:1421)
  	at com.mkyong.io.file.FileRename.main(FileRename.java:23) 

3.移动文件–Apache Commons IO

3.1 ApacheFileUtils.moveFile使用“复制和删除”机制来重命名或移动文件。此外,它做了大量的检查,确保抛出正确的异常,这是一个可靠的解决方案。

pom.xml

 <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.7</version>
  </dependency> 
 import org.apache.commons.io.FileUtils;

    //...

    File source = new File("/home/mkyong/hello.txt");
    File target = new File("/home/mkyong/newfolder/hello2.txt");

    try {

        FileUtils.moveFile(source, target);

    } catch (IOException e) {
        e.printStackTrace();
    } 

3.2 如果目标文件存在,抛出FileExistsException

 org.apache.commons.io.FileExistsException: Destination '/home/mkyong/newfolder/hello2.txt' already exists
	at org.apache.commons.io.FileUtils.moveFile(FileUtils.java:2012)
	at com.mkyong.io.file.FileRename.main(FileRename.java:39) 

3.3 如果目标目录不存在,请创建它。

4.File.renameTo(旧 IO)

遗留 IO File.renameTo()不可靠,不推荐使用,阅读 api 文档

如果File.renameTo()未能重命名或移动文件,它将返回 false,不会抛出异常,通常情况下,我们不知道哪里出错了。

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-io

参考

如何在 Java 中调整图像的大小

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-resize-an-image-in-java/

本文展示了在 Java 中调整图像大小(创建缩略图)的两种方法。

1.原始图像,544×184

下面是一个谷歌标志图像,宽度,高度544x184,以及文件大小14k。稍后,我们将调整下图的宽度和高度为新的300x150

Google logo

2.调整图像大小或创建缩略图。

这个 Java 示例使用bufferedImage.getScaledInstance() API 来调整图像的大小,我们可以传入不同的图像的提示来生成不同比例的图像。

 BufferedImage bi = ImageIO.read(input);
  Image newResizedImage = bi.getScaledInstance(width, height, Image.SCALE_SMOOTH); 

我们可以通过以下图像的提示来配置缩放图像的质量:

  1. SCALE_AREA_AVERAGING–面积平均图像缩放算法。
  2. SCALE_DEFAULT–默认图像缩放算法
  3. SCALE_FAST–优先考虑缩放速度,而不是缩放图像的平滑度。
  4. SCALE_REPLICATE–包含在 ReplicateScaleFilter 类中的图像缩放算法
  5. SCALE_SMOOTH–优先考虑缩放图像的平滑度,而不是缩放速度。

下面的例子展示了如何将上面的图片(Google logo)调整到新的宽度和高度300x150

ResizeImage1.java

 package com.mkyong.io.image;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;

public class ResizeImage1 {

    private static final int IMG_WIDTH = 300;
    private static final int IMG_HEIGHT = 150;

    public static void main(String[] args) throws IOException {

        Path source = Paths.get("C:\\test\\google.png");
        Path target = Paths.get("C:\\test\\resize.png");

        try (InputStream is = new FileInputStream(source.toFile())) {
            resize(is, target, IMG_WIDTH, IMG_HEIGHT);
        }

    }

    private static void resize(InputStream input, Path target,
                                   int width, int height) throws IOException {

        BufferedImage originalImage = ImageIO.read(input);

        /**
         * SCALE_AREA_AVERAGING
         * SCALE_DEFAULT
         * SCALE_FAST
         * SCALE_REPLICATE
         * SCALE_SMOOTH
         */
        Image newResizedImage = originalImage
              .getScaledInstance(width, height, Image.SCALE_SMOOTH);

        String s = target.getFileName().toString();
        String fileExtension = s.substring(s.lastIndexOf(".") + 1);

        // we want image in png format
        ImageIO.write(convertToBufferedImage(newResizedImage),
                fileExtension, target.toFile());

    }

    public static BufferedImage convertToBufferedImage(Image img) {

        if (img instanceof BufferedImage) {
            return (BufferedImage) img;
        }

        // Create a buffered image with transparency
        BufferedImage bi = new BufferedImage(
                img.getWidth(null), img.getHeight(null),
                BufferedImage.TYPE_INT_ARGB);

        Graphics2D graphics2D = bi.createGraphics();
        graphics2D.drawImage(img, 0, 0, null);
        graphics2D.dispose();

        return bi;
    }

} 

查看以下输出:

形象。缩放 _ 平滑

 bufferedImage.getScaledInstance(width, height, Image.SCALE_SMOOTH); 

下图显示了Image.SCALE_SMOOTH提示的使用,新缩放后的图像文件大小为14kb,与原始图像相同,但质量非常好。

resize image smooth

形象。缩放 _ 默认

 bufferedImage.getScaledInstance(width, height, Image.SCALE_DEFAULT); 

下图显示了Image.SCALE_DEFAULT提示的使用,新缩放图像的文件大小为9kb

resize image default

形象。快速缩放

 bufferedImage.getScaledInstance(width, height, Image.SCALE_FAST); 

下图显示了Image.SCALE_FAST提示的使用,新缩放图像的文件大小为9kb

resize image fast

尝试不同的提示来适应你的情况。

3.Java 调整图像大小,绘制新图像。

这个例子更加灵活(可以定制背景、颜色过滤或者渲染提示),但是需要额外的编码来绘制一个新调整大小的图像。

 BufferedImage originalImage = ImageIO.read(input);

  BufferedImage newResizedImage
        = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

  Graphics2D g = newResizedImage.createGraphics();

  // background transparent
  g.setComposite(AlphaComposite.Src);
  g.fillRect(0, 0, width, height);

  // configure RenderingHints
  g.setRenderingHint(RenderingHints.KEY_RENDERING,
                        RenderingHints.VALUE_RENDER_QUALITY);

  // draw a new image
  g.drawImage(originalImage, 0, 0, IMG_WIDTH, IMG_HEIGHT, null); 

一个完整的调整图像大小的 Java 例子。

ResizeImage2.java

 package com.mkyong.io.image;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;

public class ResizeImage2 {

    private static final int IMG_WIDTH = 300;
    private static final int IMG_HEIGHT = 150;

    public static void main(String[] args) throws IOException {

        Path source = Paths.get("C:\\test\\google.png");
        Path target = Paths.get("C:\\test\\resize.png");

        try (InputStream is = new FileInputStream(source.toFile())) {
            resize(is, target, IMG_WIDTH, IMG_HEIGHT);
        }

    }

    private static void resize(InputStream input, Path target,
                               int width, int height) throws IOException {

        // read an image to BufferedImage for processing
        BufferedImage originalImage = ImageIO.read(input);

        // create a new BufferedImage for drawing
        BufferedImage newResizedImage
              = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = newResizedImage.createGraphics();

        //g.setBackground(Color.WHITE);
        //g.setPaint(Color.WHITE);

        // background transparent
        g.setComposite(AlphaComposite.Src);
        g.fillRect(0, 0, width, height);

        /* try addRenderingHints()
        // VALUE_RENDER_DEFAULT = good tradeoff of performance vs quality
        // VALUE_RENDER_SPEED   = prefer speed
        // VALUE_RENDER_QUALITY = prefer quality
        g.setRenderingHint(RenderingHints.KEY_RENDERING,
                              RenderingHints.VALUE_RENDER_QUALITY);

        // controls how image pixels are filtered or resampled
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                              RenderingHints.VALUE_INTERPOLATION_BILINEAR);

        // antialiasing, on
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                              RenderingHints.VALUE_ANTIALIAS_ON);*/

        Map<RenderingHints.Key,Object> hints = new HashMap<>();
        hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        hints.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.addRenderingHints(hints);

        // puts the original image into the newResizedImage
        g.drawImage(originalImage, 0, 0, IMG_WIDTH, IMG_HEIGHT, null);
        g.dispose();

        // get file extension
        String s = target.getFileName().toString();
        String fileExtension = s.substring(s.lastIndexOf(".") + 1);

        // we want image in png format
        ImageIO.write(newResizedImage, fileExtension, target.toFile());

    }

} 

新缩放图像的文件大小约为13kb

resize image final

300x150的新宽度和高度

resize image properties

尝试不同的提示,找出缩放速度和缩放图像平滑度的正确平衡。

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-io

参考

如何用 Maven 运行单元测试

原文:http://web.archive.org/web/20230101150211/https://www.mkyong.com/maven/how-to-run-unit-test-with-maven/

你可以使用mvn test在 Maven 中运行单元测试。几个例子:

 # Run all the unit test classes.
$ mvn test

# Run a single test class.
$ mvn -Dtest=TestApp1 test

# Run multiple test classes.
$ mvn -Dtest=TestApp1,TestApp2 test

# Run a single test method from a test class.
$ mvn -Dtest=TestApp1#methodname test

# Run all test methods that match pattern 'testHello*' from a test class.
$ mvn -Dtest=TestApp1#testHello* test

# Run all test methods match pattern 'testHello*' and 'testMagic*' from a test class.
$ mvn -Dtest=TestApp1#testHello*+testMagic* test 

默认的maven-surefire-plugin已经过时,请确保更新到最新版本以支持新功能,如模式匹配或运行单一测试方法等。

pom.xml

 <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.0</version>
            </plugin>

        </plugins>
    </build> 

1.Maven Java 项目

回顾一个简单的 Java 项目如何在 Maven 中运行单元测试类。

1.1 目录结构。

1.2 Maven + JUnit 5 个例子。

pom.xml

 <?xml version="1.0" encoding="UTF-8"?>
<project 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
		 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mkyong.examples</groupId>
    <artifactId>maven-unit-test</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <!-- https://maven.apache.org/general.html#encoding-warning -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>

        <!-- junit 5, unit test -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.3.1</version>
            <scope>test</scope>
        </dependency>

    </dependencies>
    <build>
        <finalName>maven-unit-test</finalName>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.0</version>
            </plugin>

        </plugins>
    </build>

</project> 

1.3 两个 Java 类,稍后我们将为它创建单元测试类。

MagicBuilder.java

 package com.mkyong.examples;

public class MagicBuilder {

    public static int getLucky() {
        return 7;
    }

} 

MessageBuilder.java

 package com.mkyong.examples;

public class MessageBuilder {

    public static String getHelloWorld(){
        return "hello world";
    }

    public static int getNumber10(){
        return 10;
    }

} 

1.4MagicBuilder的测试类

TestMagicBuilder.java

 package com.mkyong.examples;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class TestMagicBuilder {

    @Test
    public void testLucky() {
        assertEquals(7, MagicBuilder.getLucky());
    }

} 

1.5MessageBuilder的测试类

pom.xml

 package com.mkyong.examples;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class TestMessageBuilder {

    @Test
    public void testHelloWorld() {
        assertEquals("hello world", MessageBuilder.getHelloWorld());
    }

    @Test
    public void testNumber10() {
        assertEquals(10, MessageBuilder.getNumber10());
    }

} 

2.Maven 测试

2.1 运行所有测试类。

Terminal

 $ mvn test

[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.mkyong.examples.TestMagicBuilder
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.004 s - in com.mkyong.examples.TestMagicBuilder
[INFO] Running com.mkyong.examples.TestMessageBuilder
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.001 s - in com.mkyong.examples.TestMessageBuilder
[INFO] 

2.2 运行单个测试类TestMessageBuilder

Terminal

 $ mvn -Dtest=TestMessageBuilder test

[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.mkyong.examples.TestMessageBuilder
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.004 s - in com.mkyong.examples.TestMessageBuilder
[INFO] 

2.3 运行测试类TestMessageBuilder中的单一测试方法testHelloWorld()

Terminal

 $ mvn -Dtest=TestMessageBuilder#testHelloWorld test

[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.mkyong.examples.TestMessageBuilder
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.004 s - in com.mkyong.examples.TestMessageBuilder
[INFO] 

下载源代码

$ git clone https://github.com/mkyong/maven-examples.git
cdmavenunittest mvn test
mvnDtest=TestMessageBuildertest mvn -Dtest=TestMessageBuilder#testHelloWorld test

参考

  1. JUnit 5
  2. 运行单一测试

如何使用 jQuery 选择单选按钮

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jquery/how-to-select-a-radio-button-with-jquery/

一个用 jQuery 动态选择单选按钮的简单例子。

一个单选按钮组,带有一个 name="sex "。

 <input type="radio" name="sex" value="Male">Male</input>
<input type="radio" name="sex" value="Female">Female</input>
<input type="radio" name="sex" value="Unknown">Unknown</input> 

1.显示选定的单选按钮值。

 $('input:radio[name=sex]:checked').val(); 

2.选择单选按钮(男性)。
单选按钮是以 0 为基的,所以'男' = '0 ','女' = '1 ','未知' = '2 '。

 $('input:radio[name=sex]:nth(0)').attr('checked',true);
or
$('input:radio[name=sex]')[0].checked = true; 

3.选择单选按钮(阴)。

 $('input:radio[name=sex]:nth(1)').attr('checked',true);
or
$('input:radio[name=sex]')[1].checked = true; 

4.选择单选按钮(未知)。

 $('input:radio[name=sex]:nth(2)').attr('checked',true);
or
$('input:radio[name=sex]')[2].checked = true; 

5.重置选定的单选按钮。

 $('input:radio[name=sex]').attr('checked',false); 

jQuery 选择单选按钮示例

 <html>
<head>
<title>jQuery select a radio button example</title>

<script type="text/javascript" src="jquery-1.3.2.min.js"></script>

</head>

<body>

<h1>jQuery select a radio button example</h1>

<script type="text/javascript">

  $(document).ready(function(){

    $("#isSelect").click(function () {

	alert($('input:radio[name=sex]:checked').val());

    });

    $("#selectMale").click(function () {

	$('input:radio[name=sex]:nth(0)').attr('checked',true);
	//$('input:radio[name=sex]')[0].checked = true;

    });

    $("#selectFemale").click(function () {

	$('input:radio[name=sex]:nth(1)').attr('checked',true);
	//$('input:radio[name=sex]')[1].checked = true;

    });

    $("#selectUnknown").click(function () {

	$('input:radio[name=sex]:nth(2)').attr('checked',true);
	//$('input:radio[name=sex]')[2].checked = true;

    });

    $("#reset").click(function () {

	$('input:radio[name=sex]').attr('checked',false);

    });

  });
</script>
</head><body>

<input type="radio" name="sex" value="Male">Male</input>
<input type="radio" name="sex" value="Female">Female</input>
<input type="radio" name="sex" value="Unknown">Unknown</input>

<br/>
<br/>
<br/>

<input type='button' value='Display Selected' id='isSelect'>
<input type='button' value='Select Male' id='selectMale'>
<input type='button' value='Select Female' id='selectFemale'>
<input type='button' value='Select Unknown' id='selectUnknown'>
<input type='button' value='Reset' id='reset'>

</body>
</html> 

http://web.archive.org/web/20190308050044if_/http://www.mkyong.com/wp-content/uploads/jQuery/jQuery-select-radio-button.html

Try Demojquery jquery selector radio button (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190308050044/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

如何在 Android 中发送电子邮件

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/how-to-send-email-in-android/

在 Android 中,可以使用Intent.ACTION_SEND调用现有的邮件客户端发送邮件。

请参见以下代码片段:

 Intent email = new Intent(Intent.ACTION_SEND);
	email.putExtra(Intent.EXTRA_EMAIL, new String[]{"youremail@yahoo.com"});		  
	email.putExtra(Intent.EXTRA_SUBJECT, "subject");
	email.putExtra(Intent.EXTRA_TEXT, "message");
	email.setType("message/rfc822");
	startActivity(Intent.createChooser(email, "Choose an Email client :")); 

这个项目是在 Eclipse 3.7 中开发的,并用三星 Galaxy S2 (Android 2.3.3)进行了测试。

Run & test on real device only.
If you run this on emulator, you will hit error message : “No application can perform this action“. This code only work on real device.

1.Android 布局

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linearLayout1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textViewPhoneNo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="To : "
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <EditText
        android:id="@+id/editTextTo"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:inputType="textEmailAddress" >

        <requestFocus />

    </EditText>

    <TextView
        android:id="@+id/textViewSubject"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Subject : "
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <EditText
        android:id="@+id/editTextSubject"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
         >
    </EditText>

    <TextView
        android:id="@+id/textViewMessage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Message : "
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <EditText
        android:id="@+id/editTextMessage"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="top"
        android:inputType="textMultiLine"
        android:lines="5" />

    <Button
        android:id="@+id/buttonSend"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Send" />

</LinearLayout> 

2.活动

发送电子邮件的完整活动类。看了一下onClick()方法,应该不言自明。

 package com.mkyong.android;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class SendEmailActivity extends Activity {

	Button buttonSend;
	EditText textTo;
	EditText textSubject;
	EditText textMessage;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		buttonSend = (Button) findViewById(R.id.buttonSend);
		textTo = (EditText) findViewById(R.id.editTextTo);
		textSubject = (EditText) findViewById(R.id.editTextSubject);
		textMessage = (EditText) findViewById(R.id.editTextMessage);

		buttonSend.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {

			  String to = textTo.getText().toString();
			  String subject = textSubject.getText().toString();
			  String message = textMessage.getText().toString();

			  Intent email = new Intent(Intent.ACTION_SEND);
			  email.putExtra(Intent.EXTRA_EMAIL, new String[]{ to});
			  //email.putExtra(Intent.EXTRA_CC, new String[]{ to});
			  //email.putExtra(Intent.EXTRA_BCC, new String[]{to});
			  email.putExtra(Intent.EXTRA_SUBJECT, subject);
			  email.putExtra(Intent.EXTRA_TEXT, message);

			  //need this to prompts email client only
			  email.setType("message/rfc822");

			  startActivity(Intent.createChooser(email, "Choose an Email client :"));

			}
		});
	}
} 

3.演示

查看默认屏幕,填写详细信息,然后单击“发送”按钮。

send email in android

它会提示您现有的电子邮件客户端进行选择。

send email in android

在这种情况下,我选择了 Gmail ,所有之前填写的详细信息将自动填充到 Gmail 客户端。

send email in androidNote
Android does not provide API to send Email directly, you have to call the existing Email client to send Email.

下载源代码

Download it – Android-Send-Email-Example.zip (16 KB)

参考

  1. 安卓意向动作 _ 发送 Javadoc

如何在安卓系统中发送短信

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/how-to-send-sms-message-in-android/

在 Android 中,你可以使用SmsManager API 或者设备的Built-in SMS应用来发送短信。在本教程中,我们将向您展示两个发送短信的基本示例:

  1. SmsManager API

     SmsManager smsManager = SmsManager.getDefault();
    	smsManager.sendTextMessage("phoneNo", null, "sms message", null, null); 
    
  2. 内置短信应用

     Intent sendIntent = new Intent(Intent.ACTION_VIEW);
    	sendIntent.putExtra("sms_body", "default content"); 
    	sendIntent.setType("vnd.android-dir/mms-sms");
    	startActivity(sendIntent); 
    

当然,两者都需要 SEND_SMS 权限。

 <uses-permission android:name="android.permission.SEND_SMS" /> 

这个项目是在 Eclipse 3.7 中开发的,并用三星 Galaxy S2 (Android 2.3.3)进行了测试。

Note
The Built-in SMS application solution is the easiest way, because you let device handle everything for you.

1.SmsManager 示例

Android 布局文件的文本框(电话号码,短信)和按钮发送短信。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linearLayout1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textViewPhoneNo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Enter Phone Number : "
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <EditText
        android:id="@+id/editTextPhoneNo"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:phoneNumber="true" >
    </EditText>

    <TextView
        android:id="@+id/textViewSMS"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Enter SMS Message : "
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <EditText
        android:id="@+id/editTextSMS"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:inputType="textMultiLine"
        android:lines="5"
        android:gravity="top" />

    <Button
        android:id="@+id/buttonSend"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Send" />

</LinearLayout> 

文件:SendSMSActivity.java——通过SmsManager发送短信的活动。

 package com.mkyong.android;

import android.app.Activity;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class SendSMSActivity extends Activity {

	Button buttonSend;
	EditText textPhoneNo;
	EditText textSMS;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		buttonSend = (Button) findViewById(R.id.buttonSend);
		textPhoneNo = (EditText) findViewById(R.id.editTextPhoneNo);
		textSMS = (EditText) findViewById(R.id.editTextSMS);

		buttonSend.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {

			  String phoneNo = textPhoneNo.getText().toString();
			  String sms = textSMS.getText().toString();

			  try {
				SmsManager smsManager = SmsManager.getDefault();
				smsManager.sendTextMessage(phoneNo, null, sms, null, null);
				Toast.makeText(getApplicationContext(), "SMS Sent!",
							Toast.LENGTH_LONG).show();
			  } catch (Exception e) {
				Toast.makeText(getApplicationContext(),
					"SMS faild, please try again later!",
					Toast.LENGTH_LONG).show();
				e.printStackTrace();
			  }

			}
		});
	}
} 

文件:AndroidManifest.xml ,需要 SEND_SMS 权限。

 <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mkyong.android"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="10" />

    <uses-permission android:name="android.permission.SEND_SMS" />

    <application
        android:debuggable="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:label="@string/app_name"
            android:name=".SendSMSActivity" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest> 

参见演示:

send sms message via smsmanager ## 2.内置短信应用示例

该示例使用设备的内置 SMS 应用程序发送 SMS 消息。

File:RES/layout/main . XML–仅一个按钮。

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linearLayout1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/buttonSend"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Send" />

</LinearLayout> 

文件:SendSMSActivity.java–使用内置短信发送短信的活动类。

 package com.mkyong.android;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class SendSMSActivity extends Activity {

	Button buttonSend;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		buttonSend = (Button) findViewById(R.id.buttonSend);

		buttonSend.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {

				try {

				     Intent sendIntent = new Intent(Intent.ACTION_VIEW);
				     sendIntent.putExtra("sms_body", "default content"); 
				     sendIntent.setType("vnd.android-dir/mms-sms");
				     startActivity(sendIntent);

				} catch (Exception e) {
					Toast.makeText(getApplicationContext(),
						"SMS faild, please try again later!",
						Toast.LENGTH_LONG).show();
					e.printStackTrace();
				}
			}
		});
	}
} 

参见演示:

send sms via build-in sms applicationsend sms via build-in sms application ## 下载源代码

Download it – 1. Android-Send-SMS-Example.zip (16 KB)Download it – 2. Android-Build-In-SMS-Application-Example.zip (16 KB)

参考

  1. Android SmsManager Javadoc
  2. Android 手机短信

android sms

如何在 jQuery 中设置下拉框值

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jquery/how-to-set-a-dropdown-box-value-in-jquery/

一个简单的选择/下拉框,id=“国家”。

 <select id="country">
   <option value="None">-- Select --</option>
   <option value="China">China</option>
   <option value="United State">United State</option>
   <option value="Malaysia">Malaysia</option>
</select> 

1.显示选定的下拉框值。

 $('#country').val(); 

2.将下拉框值设置为“中国”。

 $("#country").val("China"); 

3.将下拉框值设置为“美国”。

 $("#country").val("United State"); 

4.将下拉框值设置为“马来西亚”。

 $("#country").val("Malaysia"); 

5.禁用下拉框中的“美国”选项。

 $("#country option[value='United State']").attr("disabled", true); 

6.启用下拉框中的“美国”选项。

 $("#country option[value='United State']").attr("disabled", false); 

jQuery 选择/下拉框示例

 <html>
<head>
<title>jQuery select / dropdown box example</title>

<script type="text/javascript" src="jquery-1.3.2.min.js"></script>

</head>

<body>

<h1>jQuery select / dropdown box example</h1>

<script type="text/javascript">

  $(document).ready(function(){

    $("#isSelect").click(function () {

	alert($('#country').val());

    });

    $("#selectChina").click(function () {

	$("#country").val("China");

    });

    $("#selectUS").click(function () {

	$("#country").val("United State");

    });

    $("#selectMalaysia").click(function () {

	$("#country").val("Malaysia");

    });

    $("#disableUS").click(function () {

	$("#country option[value='United State']").attr("disabled", true);

    });

    $("#enableUS").click(function () {

	$("#country option[value='United State']").attr("disabled", false);

    });

  });
</script>
</head><body>

<select id="country">
<option value="None">-- Select --</option>
<option value="China">China</option>
<option value="United State">United State</option>
<option value="Malaysia">Malaysia</option>
</select>

<br/>
<br/>
<br/>

<input type='button' value='Display Selected' id='isSelect'>
<input type='button' value='Select China' id='selectChina'>
<input type='button' value='Select US' id='selectUS'>
<input type='button' value='Select Malaysia' id='selectMalaysia'>
<input type='button' value='Disable US' id='disableUS'>
<input type='button' value='Enable US' id='enableUS'>
</body>
</html> 

http://web.archive.org/web/20221006023910if_/https://www.mkyong.com/wp-content/uploads/jQuery/jQuery-select-dropdown-box.html

Try Demo

如何为 Android 应用程序设置默认活动

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/how-to-set-default-activity-for-android-application/

在 Android 中,您可以通过“ AndroidManifest.xml ”中的“ intent-filter ”来配置应用程序的启动活动(默认活动)。

请参见以下代码片段,将活动类" logoActivity "配置为默认活动。

文件:AndroidManifest.xml

 <activity
            android:label="Logo"
            android:name=".logoActivity" >
             <intent-filter >
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity> 

例如,假设您有两个 activity 类,并且您想要将"ListMobileActivity"活动设置为您的应用程序的起始活动。

文件:AndroidManifest.xml

 <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mkyong.android"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="10" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:label="List of Mobile OS"
            android:name=".ListMobileActivity" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:label="List of Fruits"
            android:name=".ListFruitActivity" >
        </activity>
    </application>

</manifest> 

另一方面,如果您想将“ListFruitActivity”活动设置为您的开始活动,只需剪切并粘贴“”意向过滤器,如下所示:

文件:AndroidManifest.xml

 <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mkyong.android"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="10" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:label="List of Mobile OS"
            android:name=".ListMobileActivity" >
        </activity>
        <activity
            android:label="List of Fruits"
            android:name=".ListFruitActivity" >
             <intent-filter >
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest> 

Tags : android android activityfreestar.config.enabled_slots.push({ placementName: "mkyong_leaderboard_btf", slotId: "mkyong_leaderboard_btf" });

如何在 Struts 2 中为多个复选框设置默认值

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/struts2/how-to-set-default-value-for-multiple-checkboxes-in-struts-2/

在 Struts 2 中,可以通过 < s:checkboxlist > 标签创建多个同名的复选框。棘手的部分是如何在多个复选框中设置默认值。例如,带有“红色”、“黄色”、“蓝色”、“绿色”选项的复选框列表,并且您希望将“红色”和“绿色”都设置为默认选中值。

Download It – Struts2-default-value-multiple-checkboxes-example.zip

1.举例

一个<s:checkbox list>T1 的例子

 <s:checkboxlist label="What's your favor color" list="colors" name="yourColor" /> 

产生以下 HTML 代码

 <td class="tdLabel"><label for="resultAction_yourColor" class="label">
What's your favor color:</label>
</td> 
<td > 
<input type="checkbox" name="yourColor" value="red" id="yourColor-1" /> 
<label for="yourColor-1" class="checkboxLabel">red</label> 
<input type="checkbox" name="yourColor" value="yellow" id="yourColor-2" /> 
<label for="yourColor-2" class="checkboxLabel">yellow</label> 
<input type="checkbox" name="yourColor" value="blue" id="yourColor-3" /> 
<label for="yourColor-3" class="checkboxLabel">blue</label> 
<input type="checkbox" name="yourColor" value="green" id="yourColor-4" /> 
<label for="yourColor-4" class="checkboxLabel">green</label> 
<input type="hidden" id="__multiselect_resultAction_yourColor" 
 name="__multiselect_yourColor" value="" />     
</td> 

操作类为复选框提供颜色选项列表。

 //...
public class CheckBoxListAction extends ActionSupport{

	private List<String> colors;
	private String yourColor;

	public CheckBoxListAction(){

		colors = new ArrayList<String>();
		colors.add("red");
		colors.add("yellow");
		colors.add("blue");
		colors.add("green");
	}

	public List<String> getColors() {
		return colors;
	}
	//...
} 

2.单一默认检查值

要将“ red 选项设置为默认选中值,只需在 Action 类中添加一个方法,并返回一个“ red 值。

 //...
public class CheckBoxListAction extends ActionSupport{

	//add a new method
	public String getDefaultColor(){
		return "red";
	}
} 

< s:checkboxlist >标签中,添加一个 value 属性,并指向 getDefaultColor() 方法。

 <s:checkboxlist label="What's your favor color" list="colors" 
     name="yourColor" value="defaultColor" /> 

Struts 2 is intelligent enough to match the “defaultColor” value to the correspond Java property getDefaultColor().

再次运行它,默认情况下“红色”选项将被选中。

2.多个默认选中值

要将多个值“红色”和“绿色”设置为默认检查值,只需返回一个“字符串[] ”而不是一个“字符串”,Struts 2 就会相应地匹配它。

 //...
public class CheckBoxListAction extends ActionSupport{

	//now return a String[]
	public String[] getDefaultColor(){
		return new String [] {"red", "green"};
	}
} 
 <s:checkboxlist label="What's your favor color" list="colors" 
     name="yourColor" value="defaultColor" /> 

再次运行,默认勾选“红色”和“绿色”选项。

checkbox struts2

maven——如何跳过单元测试

原文:http://web.archive.org/web/20230101150211/https://www.mkyong.com/maven/how-to-skip-maven-unit-test/

在 Maven 中,您可以定义一个系统属性-Dmaven.test.skip=true来跳过整个单元测试。

默认情况下,在构建项目时,Maven 会自动运行整个单元测试。如果任何单元测试失败,它将迫使 Maven 中止构建过程。在现实生活中,即使有些案例失败了,你可能仍然需要构建你的项目。

在本文中,我们将向您展示几种跳过单元测试的方法。

1.maven.test.skip=true

1.1 为了跳过单元测试,使用了这个参数-Dmaven.test.skip=true

Terminal

 $ mvn package -Dmaven.test.skip=true
#no test 

1.2 或在pom.xml中定义

pom.xml

 <properties>
        <maven.test.skip>true</maven.test.skip>
    </properties> 

Terminal

 $ mvn package
#no test 

2.Maven Surefire 插件

2.1 或者,在 surefire 插件中使用这个-DskipTests

Terminal

 $ mvn package -DskipTests
#no test 

2.2 或者这个。

pom.xml

 <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.0.0-M1</version>
    <configuration>
        <skipTests>true</skipTests>
    </configuration>
</plugin> 

2.3 跳过一些测试类。

pom.xml

 <plugin>
		<groupId>org.apache.maven.plugins</groupId>
		<artifactId>maven-surefire-plugin</artifactId>
		<version>3.0.0-M1</version>
		<configuration>
			<excludes>
				<exclude>**/TestMagic*.java</exclude>
				<exclude>**/TestMessage*.java</exclude>
			</excludes>
		</configuration>
    </plugin> 

3.Maven 简介

3.1 创建一个自定义概要文件来跳过单元测试。

pom.xml

 <profiles>
        <profile>
			<id>xtest</id>
			<properties>
				<maven.test.skip>true</maven.test.skip>
			</properties>
		</profile>
    </profiles> 

3.2 使用-P选项激活轮廓。

Terminal

 $ mvn package -Pxtest
#no test 

参考

  1. Maven Surefire 插件
  2. 试验的包含和排除
  3. 跳过测试
  4. Maven 概要示例
  5. 如何用 Maven 运行单元测试

如何在 JSF 跳过验证

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/how-to-skip-validation-in-jsf/

问题

参见下面 JSF 的例子:

 <h:inputSecret id="password" value="#{user.password}" 
		size="20" required="true" label="Password">	
		<f:validateRegex pattern="((?=.*\d).{6,20})" />
	</h:inputSecret>

	<h:message for="password" style="color:red" />

	<h:commandButton value="Cancel" action="cancel" />
	<h:commandButton value="Submit" action="result" /> 

如果您单击“取消”按钮,密码验证将被触发,并阻止您继续进入取消页面,这是没有意义的。有没有办法绕过 JSF 的验证?

解决办法

要跳过验证,向 cancel 按钮添加一个 immediate="true" 属性。

 <h:inputSecret id="password" value="#{user.password}" 
		size="20" required="true" label="Password">			
	</h:inputSecret>

	<h:message for="password" style="color:red" />

	<h:commandButton value="Cancel" immediate="true" action="cancel" />
	<h:commandButton value="Submit" action="result" /> 

jsf2 validation (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190116132727/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

如何将 faces-config.xml 拆分成多个文件?

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/how-to-split-faces-config-xml-into-multiple-files/

问题

在 JSF, faces-config.xml 文件可以用来包含管理 beans、导航规则或任何 JSF faces 配置。但是,将所有的配置放入一个单独的 faces-config.xml 文件中会导致这个文件很快变大,并导致严重的可维护性问题。

解决办法

实际上,您可以将 faces-config.xml 分割成多个更小的文件,每个文件根据相关的设置进行分组。例如,按模块分组、受管 beans、导航规则、不同 XML 文件中的 faces 配置。见下图:

jsf2-multiple-faces-config-files

然后声明了所有 XML 文件中的javax . faces . config _ FILESinitialize 参数,它在 WEB-INF/web.xm l 文件里面。

 <web-app ...>
  ...
  <context-param>
    <param-name>javax.faces.CONFIG_FILES</param-name>
    <param-value>
    	WEB-INF/common/manage-beans.xml,
    	WEB-INF/common/navigation-rule.xml,
    	WEB-INF/common/config.xml
    </param-value>
  </context-param>
  ...
</web-app> 

Note
For Struts developer, this is the exact classic problem happened in the Struts configuration file as well.

如何用 jQuery 阻止页面退出或卸载

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jquery/how-to-stop-a-page-from-exit-or-unload-with-jquery/

当页面退出或卸载时,' unload '事件将被激活,但是该事件不能阻止页面退出。

 $(window).bind('unload', function(){}); 

从 jQuery 1.4 开始,您可以将“ beforeunload ”事件绑定到$(windows)对象,以阻止页面退出、卸载或导航。

 $(window).bind('beforeunload', function(){ 
	return '';
}); 

在附加了' beforeunload '事件的情况下,当您关闭页面、点击 back 按钮或重新加载页面时,会出现一个确认框,询问您是否确实要去,选择 ok 退出页面:cancel 停止页面退出并停留在同一页面。

此外,您还可以在确认框中添加自己的信息:

 $(window).bind('beforeunload', function(){
	return '>>>>>Before You Go<<<<<<<< \n Your custom message go here';
}); 

另外,从 jQuery 1.4 开始支持“卸载前”事件

你自己试试

 <html>
<head>
<title>Refresh a page in jQuery</title>

<script type="text/javascript" src="jquery-1.4.2.min.js"></script>

</head>

<body>

<h1>Stop a page from exit with jQuery</h1>

<button id="reload">Refresh a Page in jQuery</button>

<script type="text/javascript">

	$('#reload').click(function() {

	 	location.reload();

	});

	$(window).bind('beforeunload', function(){
		return '>>>>>Before You Go<<<<<<<< \n Your custom message go here';
	});

</script>

</body>
</html> 

Try Demojquery (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190227163517/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

Java–将属性文件转换为 XML

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-store-properties-into-xml-file/

在 Java 中,我们可以使用Properties#storeToXML()将属性值转换成 XML 文件。

目录

用 Java 11 测试。

1。将属性值转换为 XML 文件

以下示例创建了一些属性值,并将它们存储为 XML 文件。

PropertiesToXml.java

 package com.mkyong.xml.tips;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Properties;

public class PropertiesToXml {

  public static void main(String[] args) throws IOException {

      // create some properties values on demand
      Properties props = new Properties();
      props.setProperty("email.support", "donot-spam-me@nospam.com");
      props.setProperty("http.port", "8080");
      props.setProperty("http.server", "localhost");

      try (OutputStream output =
          new FileOutputStream("c:\\test\\server-config.xml")) {

          // convert the properties to an XML file
          props.storeToXML(output, "Server config file", StandardCharsets.UTF_8);

      }

  }

} 

输出

c:\test\server-config.xml

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>Server config file</comment>
<entry key="http.port">8080</entry>
<entry key="email.support">donot-spam-me@nospam.com</entry>
<entry key="http.server">localhost</entry>
</properties> 

2。将属性文件转换成 XML 文件

下面的例子加载了一个.properties文件并将它们存储为一个 XML 文件。

application.properties

 greeting.message=hello
quarkus.http.port=8080 

PropertiesToXml2.java

 package com.mkyong.xml.tips;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Properties;

public class PropertiesToXml2 {

  public static void main(String[] args) throws IOException {

      Properties props = new Properties();
      try (InputStream input =
            new FileInputStream("src/main/resources/application.properties")) {
          // loads a properties file
          props.load(input);
      }

      try (OutputStream output =
            new FileOutputStream("c:\\test\\server-config.xml")) {

          // convert the properties to an XML file
          props.storeToXML(output, "Server config file",
                  StandardCharsets.UTF_8);

      }

  }

} 

输出

c:\test\server-config.xml

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>Server config file</comment>
<entry key="greeting.message">hello</entry>
<entry key="quarkus.http.port">8080</entry>
</properties> 

3。下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-xml

$ CD src/main/Java/com/mkyong/XML/tips/

4。参考文献

如何告诉 Maven 使用 Java 8

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/maven/how-to-tell-maven-to-use-java-8/

pom.xml中,定义了这个maven.compiler.source属性来告诉 Maven 使用 Java 8 来编译项目。

1.Maven 属性

Java 8

pom.xml

 <properties>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
    </properties> 

Java 7

pom.xml

 <properties>
        <maven.compiler.target>1.7</maven.compiler.target>
        <maven.compiler.source>1.7</maven.compiler.source>
    </properties> 

2.编译器插件

或者,直接配置插件。

pom.xml

 <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build> 

参考

  1. Maven–设置 Java 编译器的-source 和-target
  2. 如何用不同的 JDK 版本编译 Maven 项目?

compiler java 8 maven

如何在 Eclipse IDE 中跟踪 SOAP 消息

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/webservices/jax-ws/how-to-trace-soap-message-in-eclipse-ide/

在 SOAP web 服务中,每个 HTTP 请求或响应都封装了一个 SOAP 信封,使用 Eclipse IDE 内置的" TCP/IP monitor "工具可以很容易地跟踪这些消息。这个想法是在客户端和服务器之间托管另一个服务器,以执行端口转发功能来拦截 HTTP 流量。

1.正常的 SOAP 信封流

在普通的 SOAP 服务中,客户端向服务器发送 HTTP 请求,服务器直接向客户端发回 HTTP 响应。

 1\. Client ----> SOAP envelope ----> Server:9999

2\. Server:9999 ----> SOAP envelope ---> Client 

2.拦截的 SOAP 信封流

要拦截 SOAP 信封,您可以在客户端和服务器之间托管另一个服务器(“TcpMonitorServer”),请参见新流:

 1\. Client ----> SOAP envelope ----> TcpMonitorServer:8888

2\. TcpMonitorServer:8888 --> SOAP envelope ---> Server:9999

3\. Server:9999 ----> SOAP envelope ---> TcpMonitorServer:8888

4\. TcpMonitorServer:8888 ----> SOAP envelope ---> Client 

Note
This method required port changed in your web service client. ## Eclipse IDE + TCP/IP 监视器

Eclipse IDE 附带了一个非常容易使用的流量拦截工具,称为“ TCP/IP Monitor ”。在本教程中,我们将向您展示如何在 Eclipse IDE 中启用这个“TCP/IP 监视器”,以及如何截取 web 服务生成的 SOAP 消息。

下面是在 Eclispe IDE 中启用“TCP/IP Monitor”的步骤。

1.在 IDE 中,进入窗口–>首选项–>运行/调试–>TCP/IP 监控

eclipse-trace-soap-example1

2.填写服务器信息,选择 type = " TCP/IP

eclipse-trace-soap-example2

3.单击“开始”按钮开始跟踪 web 服务流量。

eclipse-trace-soap-example3

4.在“TCP/IP 监视器”视图中显示跟踪的消息(如果有)。

eclipse-trace-soap-example4Note
You can copy this JAX-WS web service example and do the testing yourself.For Netbean users
In Netbean IDE, you can use TCP monitor to trace SOAP message.eclipse jax-ws soap web services

如何手动触发 Quartz 作业(JSF 2 示例)

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/jsf2/how-to-trigger-a-quartz-job-manually-jsf-2-example/

在 Quartz 中,您可以通过以下模式手动触发作业:

 JobKey jobKey = new JobKey(jobName, jobGroup);
scheduler.triggerJob(jobKey); //trigger a job by jobkey 

在本教程中,我们将向您展示一个 JSF 2 web 应用程序,显示dataTable上的所有 Quartz 作业,并允许用户点击一个链接来手动启动作业。

使用的工具:

  1. JSF 2.1.11
  2. 石英 2.1.5
  3. Eclipse 4.2
  4. maven3
  5. 在 Tomcat 6 和 7 上测试

1.项目目录

最终项目目录。

final project directory ## 2.项目依赖性

本教程的所有依赖项。

文件:pom.xml

 <project ...>

		<dependency>
			<groupId>com.sun.faces</groupId>
			<artifactId>jsf-api</artifactId>
			<version>2.1.11</version>
		</dependency>
		<dependency>
			<groupId>com.sun.faces</groupId>
			<artifactId>jsf-impl</artifactId>
			<version>2.1.11</version>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
		</dependency>

		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.1</version>
		</dependency>

		<!-- solve method not found error in tomcat --> 
		<dependency>
			<groupId>org.glassfish.web</groupId>
			<artifactId>el-impl</artifactId>
			<version>2.2</version>
		</dependency>

		<dependency>
			<groupId>com.sun.el</groupId>
			<artifactId>el-ri</artifactId>
			<version>1.0</version>
		</dependency>

		<!-- Quartz scheduler framework -->
		<dependency>
			<groupId>org.quartz-scheduler</groupId>
			<artifactId>quartz</artifactId>
			<version>2.1.5</version>
		</dependency>

		<dependency>
			<groupId>javax.transaction</groupId>
			<artifactId>jta</artifactId>
			<version>1.1</version>
		</dependency>

	</dependencies>

</project> 

3.石英工作

通过web.xml中的监听器,创造两份工作并与 JSF 整合。

 package com.mkyong.jobs;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class JobA implements Job {

	@Override
	public void execute(JobExecutionContext context)
		throws JobExecutionException {
		System.out.println("Job A is runing");

	}

} 
 package com.mkyong.jobs;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class JobB implements Job {

	@Override
	public void execute(JobExecutionContext context)
		throws JobExecutionException {
		System.out.println("Job B is runing");

	}

} 

文件:quartz.properties

 org.quartz.scheduler.instanceName = MyScheduler
org.quartz.threadPool.threadCount = 3
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
org.quartz.plugin.jobInitializer.class =org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin 
org.quartz.plugin.jobInitializer.fileNames = quartz-config.xml 
org.quartz.plugin.jobInitializer.failOnFileNotFound = true 

文件:quartz.config

 <?xml version="1.0" encoding="UTF-8"?>
<job-scheduling-data

	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData 
	http://www.quartz-scheduler.org/xml/job_scheduling_data_1_8.xsd"
	version="1.8">

	<schedule>
		<job>
			<name>JobA</name>
			<group>GroupDummy</group>
			<description>This is Job A</description>
			<job-class>com.mkyong.jobs.JobA</job-class>
		</job>

		<trigger>
			<cron>
				<name>dummyTriggerNameA</name>
				<job-name>JobA</job-name>
				<job-group>GroupDummy</job-group>
				<!-- It will run every 30 seconds -->
				<cron-expression>0/30 * * * * ?</cron-expression>
			</cron>
		</trigger>
	</schedule>

	<schedule>
		<job>
			<name>JobB</name>
			<group>GroupDummy</group>
			<description>This is Job B</description>
			<job-class>com.mkyong.jobs.JobB</job-class>
		</job>

		<trigger>
			<cron>
				<name>dummyTriggerNameB</name>
				<job-name>JobB</job-name>
				<job-group>GroupDummy</job-group>
				<!-- It will run every 30 seconds -->
				<cron-expression>0/30 * * * * ?</cron-expression>
			</cron>
		</trigger>
	</schedule>
</job-scheduling-data> 

文件:web.xml

 <?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

	xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	id="WebApp_ID" version="2.5">

	<display-name>JavaServerFaces</display-name>

	<!-- Change to "Production" when you are ready to deploy -->
	<context-param>
		<param-name>javax.faces.PROJECT_STAGE</param-name>
		<param-value>Development</param-value>
	</context-param>

	<!-- Welcome page -->
	<welcome-file-list>
		<welcome-file>faces/welcome.xhtml</welcome-file>
	</welcome-file-list>

	<!-- JSF mapping -->
	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<!-- Map these files with JSF -->
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>/faces/*</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.jsf</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.faces</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.xhtml</url-pattern>
	</servlet-mapping>

	<listener>
		<listener-class>
			org.quartz.ee.servlet.QuartzInitializerListener
		</listener-class>
	</listener>

</web-app> 

4.JSF 豆

一个 JSF 比恩为后来的dataTable提供数据。在构造函数中,获取所有现有的作业并添加到一个列表中,然后返回它。

 package com.mkyong.scheduler;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;

import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.ee.servlet.QuartzInitializerListener;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;

@ManagedBean(name = "scheduler")
@SessionScoped
public class SchedulerBean implements Serializable {

	private static final long serialVersionUID = 1L;

	private Scheduler scheduler;

	private List<QuartzJob> quartzJobList = new ArrayList<QuartzJob>();

	public SchedulerBean() throws SchedulerException {

	  ServletContext servletContext = (ServletContext) FacesContext
		.getCurrentInstance().getExternalContext().getContext();

	  //Get QuartzInitializerListener 
	  StdSchedulerFactory stdSchedulerFactory = (StdSchedulerFactory) servletContext
		.getAttribute(QuartzInitializerListener.QUARTZ_FACTORY_KEY);

	  scheduler = stdSchedulerFactory.getScheduler();

	  // loop jobs by group
	  for (String groupName : scheduler.getJobGroupNames()) {

		// get jobkey
		for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher
			.jobGroupEquals(groupName))) {

			String jobName = jobKey.getName();
			String jobGroup = jobKey.getGroup();

			// get job's trigger
			List<Trigger> triggers = (List<Trigger>) scheduler
				.getTriggersOfJob(jobKey);
			Date nextFireTime = triggers.get(0).getNextFireTime();

			quartzJobList.add(new QuartzJob(jobName, jobGroup, nextFireTime));

		}

	  }

	}

	//trigger a job
	public void fireNow(String jobName, String jobGroup)
		throws SchedulerException {

		JobKey jobKey = new JobKey(jobName, jobGroup);
		scheduler.triggerJob(jobKey);

	}

	public List<QuartzJob> getQuartzJobList() {

		return quartzJobList;

	}

	public static class QuartzJob {

		private static final long serialVersionUID = 1L;

		String jobName;
		String jobGroup;
		Date nextFireTime;

		public QuartzJob(String jobName, String jobGroup, Date nextFireTime) {

			this.jobName = jobName;
			this.jobGroup = jobGroup;
			this.nextFireTime = nextFireTime;
		}

		public String getJobName() {
			return jobName;
		}

		public void setJobName(String jobName) {
			this.jobName = jobName;
		}

		public String getJobGroup() {
			return jobGroup;
		}

		public void setJobGroup(String jobGroup) {
			this.jobGroup = jobGroup;
		}

		public Date getNextFireTime() {
			return nextFireTime;
		}

		public void setNextFireTime(Date nextFireTime) {
			this.nextFireTime = nextFireTime;
		}

	}

} 

5.JSF 页面

一个网页,通过 EL #{scheduler.quartzJobList}获取所有已有的作业,通过dataTable组件显示。当单击“fireNow”链接时,它将立即启动指定的作业。

文件:welcome.xhtml

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html 
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
	<h:outputStylesheet library="css" name="table-style.css" />
</h:head>
<h:body>

  <h1>All Quartz Jobs</h1>
  <h:form>
	<h:dataTable value="#{scheduler.quartzJobList}" var="quartz"
		styleClass="quartz-table" headerClass="quartz-table-header"
		rowClasses="quartz-table-odd-row,quartz-table-even-row">

		<h:column>
		  <!-- column header -->
		  <f:facet name="header">Job Name</f:facet>
		  <!-- row record -->
    		  #{quartz.jobName}
    		</h:column>

		<h:column>
		  <f:facet name="header">Job Group</f:facet>
    		  #{quartz.jobGroup}
    		</h:column>

		<h:column>
		  <f:facet name="header">Next Fire Time</f:facet>
		  <h:outputText value="#{quartz.nextFireTime}">
		      <f:convertDateTime pattern="dd.MM.yyyy HH:mm" />
		  </h:outputText>
		</h:column>

		<h:column>
		  <f:facet name="header">Action</f:facet>
		  <h:commandLink value="Fire Now"
		     action="#{scheduler.fireNow(quartz.jobName, quartz.jobGroup)}" />
		</h:column>

	   </h:dataTable>
	</h:form>
</h:body>
</html> 

文件:table-style.css

 .quartz-table{   
	border-collapse:collapse;
}

.quartz-table-header{
	text-align:center;
	background:none repeat scroll 0 0 #E5E5E5;
	border-bottom:1px solid #BBBBBB;
	padding:16px;
}

.quartz-table-odd-row{
	text-align:center;
	background:none repeat scroll 0 0 #FFFFFFF;
	border-top:1px solid #BBBBBB;
	padding:20px;
}

.quartz-table-even-row{
	text-align:center;
	background:none repeat scroll 0 0 #F9F9F9;
	border-top:1px solid #BBBBBB;
	padding:20px;
} 

6.演示

请参见最终输出。http://localhost:8080/Java server faces/

list all quartz jobs

下载源代码

Download it – JSF-Quartz-Trigger-Job-Manually.zip (28 kb)

参考

  1. Quartz 2 管理员页面示例
  2. 石英 2 + JSF 2 集成示例
  3. jquartzinitializer listener JavaDoc
  4. 石英中的多项工作

jsf2 quartz scheduler

如何用 jQuery 触发其他元素事件处理程序

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jquery/how-to-trigger-other-elements-event-handler-with-jquery/

jQuery 附带了一个 trigger() 函数来执行附加到元素的事件处理程序。举个例子,

单击事件绑定到 Id 为“button1”按钮。

 $("#button1").bind("click", (function () {

	alert("Button 1 is clicked!");

})); 

单击事件绑定到 Id 为“button2”按钮。以及执行 button1 click 事件处理程序的触发器。

 $("#button2").bind("click", (function () {

	alert("Button 2 is clicked!");

	$("#button1").trigger("click");

})); 

当点击按钮 2 时,警告消息“按钮 2 被点击!”是提示,随后是按钮 1 警告消息“按钮 1 被点击!’。

你自己试试

 <html>
<head>

<script type="text/javascript" src="jquery-1.4.2.min.js"></script>

</head>

<body>

<h1>jQuery trigger() example</h1>

<script type="text/javascript">

  $(document).ready(function(){

    $("#button1").bind("click", (function () {

	alert("Button 1 is clicked!");

    }));

    $("#button2").bind("click", (function () {

	alert("Button 2 is clicked!");

	$("#button1").trigger("click");

    }));

  });
</script>
</head><body>

<input type='button' value='Button 1' id='button1'>
<input type='button' value='Button 2' id='button2'>

</body>
</html> 

http://web.archive.org/web/20190309091056if_/http://www.mkyong.com/wp-content/uploads/jQuery/jQuery-trigger-example.html

Try Demojquery jquery event handler (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190309091056/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

如何在 Android 中打开/关闭相机 LED /闪光灯

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/how-to-turn-onoff-camera-ledflashlight-in-android/

在本教程中,我们将向您展示如何在 Android 中打开/关闭手机摄像头 led 或手电筒。查看代码片段:

1。打开

 camera = Camera.open();
	Parameters p = camera.getParameters();
	p.setFlashMode(Parameters.FLASH_MODE_TORCH);
	camera.setParameters(p);
	camera.startPreview(); 

2。关闭

 camera = Camera.open();
	Parameters p = camera.getParameters();
	p.setFlashMode(Parameters.FLASH_MODE_OFF);
	camera.setParameters(p);
	camera.stopPreview(); 

并且,在AndroidManifest.xml上设置以下权限。

 <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" /> 

P.S 这个项目是在 Eclipse 3.7 中开发的,用三星 Galaxy S2 (Android 2.3.3)测试过。

1.Android 布局

只有一个按钮。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/relativeLayout1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <Button
        android:id="@+id/buttonFlashlight"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
       	android:layout_centerVertical="true"
       	android:layout_centerHorizontal="true"
        android:text="Torch" />

</RelativeLayout> 

2.活动

看代码,一个开/关手电筒的按钮,应该不言自明。

 package com.mkyong.android;

import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class FlashLightActivity extends Activity {

	//flag to detect flash is on or off
	private boolean isLighOn = false;

	private Camera camera;

	private Button button;

	@Override
	protected void onStop() {
		super.onStop();

		if (camera != null) {
			camera.release();
		}
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		button = (Button) findViewById(R.id.buttonFlashlight);

		Context context = this;
		PackageManager pm = context.getPackageManager();

		// if device support camera?
		if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
			Log.e("err", "Device has no camera!");
			return;
		}

		camera = Camera.open();
		final Parameters p = camera.getParameters();

		button.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {

				if (isLighOn) {

					Log.i("info", "torch is turn off!");

					p.setFlashMode(Parameters.FLASH_MODE_OFF);
					camera.setParameters(p);
					camera.stopPreview();
					isLighOn = false;

				} else {

					Log.i("info", "torch is turn on!");

					p.setFlashMode(Parameters.FLASH_MODE_TORCH);

					camera.setParameters(p);
					camera.startPreview();
					isLighOn = true;

				}

			}
		});

	}
} 

3.Android 权限

分配摄像机权限。

文件:AndroidManifest.xml

 <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mkyong.android"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="10" />

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" />

    <application
        android:debuggable="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:label="@string/app_name"
            android:name=".FlashLightActivity" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest> 

4.演示

没有,直到我有二手手机来捕捉我的手机上当前的手电筒:)

下载源代码

Download it – Android-LED-FlashLight-Example.zip (16 KB)

参考

  1. 安卓摄像头 Javadoc
  2. Android 摄像头参数 Javadoc

android flashlight led

如何更新 JSF 数据表中的行

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/how-to-update-row-in-jsf-datatable/

这个例子增强了前面的 JSF 2 数据表例子,通过添加一个更新函数来更新数据表中的行。

更新概念

整体概念非常简单:

1.添加一个“ediatble”属性来跟踪行编辑状态。

 //...
public class Order{

	String orderNo;
	String productName;
	BigDecimal price;
	int qty;

	boolean editable;

	public boolean isEditable() {
		return editable;
	}
	public void setEditable(boolean editable) {
		this.editable = editable;
	} 

2.在每一行的末尾分配一个“编辑”链接,如果点击,设置“ediatble”= true。在 JSF 2.0 中,您可以直接在方法表达式中提供参数值,请参见下面的编辑操作:

 //...
<h:dataTable value="#{order.orderList}" var="o">

<h:column>

    	<f:facet name="header">Action</f:facet>

    	<h:commandLink value="Edit" action="#{order.editAction(o)}" rendered="#{not o.editable}" />

</h:column> 
 //...
public String editAction(Order order) {

	order.setEditable(true);
	return null;
} 

3.在 JSF 页面中,如果“edia tble”= true,显示输入文本框进行编辑;否则,只显示正常的输出文本。一个简单的模拟更新效果的小技巧:)

 //...
<h:dataTable value="#{order.orderList}" var="o">

<h:column>

    <f:facet name="header">Order No</f:facet>

    <h:inputText value="#{o.orderNo}" size="10" rendered="#{o.editable}" />

    <h:outputText value="#{o.orderNo}" rendered="#{not o.editable}" />

</h:column> 

4.最后,提供一个按钮来保存您的更改。当您在输入文本框中进行更改并保存时,所有值将自动绑定到相关的支持 bean。

 //...
<h:commandButton value="Save Changes" action="#{order.saveAction}" />
</h:column> 

例子

一个 JSF 2.0 的例子来实现上述概念,以更新数据表中的行。

1.受管 Bean

一个名为“order”的托管 bean,不言自明。

 package com.mkyong;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean(name="order")
@SessionScoped
public class OrderBean implements Serializable{

	private static final long serialVersionUID = 1L;

	private static final ArrayList<Order> orderList = 
		new ArrayList<Order>(Arrays.asList(

		new Order("A0001", "Intel CPU", 
				new BigDecimal("700.00"), 1),
		new Order("A0002", "Harddisk 10TB", 
				new BigDecimal("500.00"), 2),
		new Order("A0003", "Dell Laptop", 
				new BigDecimal("11600.00"), 8),
		new Order("A0004", "Samsung LCD", 
				new BigDecimal("5200.00"), 3),
		new Order("A0005", "A4Tech Mouse", 
				new BigDecimal("100.00"), 10)
	));

	public ArrayList<Order> getOrderList() {
		return orderList;
	}

	public String saveAction() {

		//get all existing value but set "editable" to false 
		for (Order order : orderList){
			order.setEditable(false);
		}
		//return to current page
		return null;

	}

	public String editAction(Order order) {

		order.setEditable(true);
		return null;
	}

	public static class Order{

		String orderNo;
		String productName;
		BigDecimal price;
		int qty;
		boolean editable;

		public Order(String orderNo, String productName, BigDecimal price, int qty) {
			this.orderNo = orderNo;
			this.productName = productName;
			this.price = price;
			this.qty = qty;
		}

		//getter and setter methods
	}
} 

2.JSF·佩奇

JSF 页面显示带有 dataTable 标记的数据,并创建一个“编辑”链接来更新行记录。

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html    
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      >
    <h:head>
    	<h:outputStylesheet library="css" name="table-style.css"  />
    </h:head>
    <h:body>

    	<h1>JSF 2 dataTable example</h1>
    	<h:form>
    	   <h:dataTable value="#{order.orderList}" var="o"
    		styleClass="order-table"
    		headerClass="order-table-header"
    		rowClasses="order-table-odd-row,order-table-even-row"
    	   >

    	     <h:column>

                <f:facet name="header">Order No</f:facet>

    		<h:inputText value="#{o.orderNo}" size="10" rendered="#{o.editable}" />

    		<h:outputText value="#{o.orderNo}" rendered="#{not o.editable}" />

    	     </h:column>

    	     <h:column>

    		<f:facet name="header">Product Name</f:facet>

    		<h:inputText value="#{o.productName}" size="20" rendered="#{o.editable}" />

    		<h:outputText value="#{o.productName}" rendered="#{not o.editable}" />

    	     </h:column>

    	     <h:column>

    		<f:facet name="header">Price</f:facet>

    		<h:inputText value="#{o.price}" size="10" rendered="#{o.editable}" />

    		<h:outputText value="#{o.price}" rendered="#{not o.editable}" />

    	     </h:column>

    	     <h:column>

    		<f:facet name="header">Quantity</f:facet>

    		<h:inputText value="#{o.qty}" size="5" rendered="#{o.editable}" />

    		<h:outputText value="#{o.qty}" rendered="#{not o.editable}" />

    	     </h:column>

    	     <h:column>

    		<f:facet name="header">Action</f:facet>

    		<h:commandLink value="Edit" action="#{order.editAction(o)}" 
                                       rendered="#{not o.editable}" />

    	     </h:column>

    	  </h:dataTable>

    	  <h:commandButton value="Save Changes" action="#{order.saveAction}" />

      </h:form>
    </h:body>	
</html> 

3.演示

从上到下,显示正在更新的行记录。

jsf2-dataTable-Update-Example-1jsf2-dataTable-Update-Example-2jsf2-dataTable-Update-Example-3jsf2-dataTable-Update-Example-4

下载源代码

Download It – JSF-2-DataTable-Update-Example.zip (10KB)datatable jsf2 update

如何在 JSF 2.0 中使用注释

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/how-to-use-comments-in-jsf-2-0/

问题

在 JSF 2.0 中,注释掉一个 JSF 标签,如下所示

JSF…

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html    
      xmlns:h="http://java.sun.com/jsf/html"
      >
     <h:body>

     <!-- 
    	<h:commandButton type="button" 
    		value="#{msg.buttonLabel}" />
      -->

    </h:body>
</html> 

但是 JSF 仍然处理值表达式并将结果输出到生成的 HTML 页面。假设 #{msg.buttonLabel} 正在返回“提交”消息。

生成的 HTML 页面…

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html >
   <body> 
     <!-- 
    	<h:commandButton type="button" 
    		value="Submit" />
      -->
   </body> 
</html> 

有没有办法完全注释掉 JSF 标签?没有对值表达式进行处理或者出现在最终生成的 HTML 页面中?

freestar.config.enabled_slots.push({ placementName: "mkyong_incontent_1", slotId: "mkyong_incontent_1" });

解决办法

有两种方法可以注释掉 JSF 标记:

1.facelets。跳过评论

在 web.xml 中,设置“ facelets。SKIP_COMMENTS 参数为 true

 <context-param>
    <param-name>facelets.SKIP_COMMENTS</param-name>
    <param-value>true</param-value>
</context-param> 

现在,JSF 删除页面中包含在 <中的任何内容!–—>

JSF…

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html    
      xmlns:h="http://java.sun.com/jsf/html"
      >
     <h:body>

      <!-- 
    	<h:commandButton type="button" 
    		value="#{msg.buttonLabel}" />
       -->

     </h:body>
</html> 

生成的 HTML 页面…

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html >
	<body> 

	</body> 
</html> 

2.用户界面:删除

或者,您可以使用“ ui:remove ”标签来定义您想要删除的内容。举个例子,

JSF

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html    
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      >
      <h:body>

        <ui:remove>
    	  <h:commandButton type="button" 
    		value="#{msg.buttonLabel}" />
        </ui:remove>

      </h:body>
</html> 

生成的 HTML 页面…

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html >
	<body> 

	</body> 
</html> 

下载源代码

Download It – JSF-2-Remove-Tag-Example.zip (10KB)

参考

  1. JSF " ui:remove " JavaDoc

标签:JSF 2freestar . config . enabled _ slots . push({ placement name:" mkyong _ leader board _ btf ",slotId:" mkyong _ leader board _ btf " });【T12

Hibernate 中如何使用数据库保留关键字?

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/how-to-use-database-reserved-keyword-in-hibernate/

在 Hibernate 中,当您试图将一个对象保存到一个以任何数据库保留关键字作为列名的表中时,您可能会遇到以下错误…

 ERROR JDBCExceptionReporter:78 - You have an error in your SQL syntax; 
check the manual that corresponds to your MySQL server version for the 
right syntax to use near 'Datadabase reserved keyword.... 

保留关键字“DESC”

在 MySQL 中,“DESC”是保留关键字。让我们看一些例子来演示如何在 Hibernate 中使用这个保留关键字。

Hibernate XML 映射文件

这是表列的默认 XML 映射文件实现,它将导致 JDBCException…

 <property name="desc" type="string" >
            <column name="DESC" length="255" not-null="true" />
        </property> 

解决办法

1.用方括号[]将关键字括起来。

 <property name="desc" type="string" >
            <column name="[DESC]" length="255" not-null="true" />
        </property> 

2.使用单引号(')将双引号(")括起来

 <property name="desc" type="string" >
            <column name='"DESC"' length="255" not-null="true" />
        </property> 

Hibernate 注释

这是表列的默认注释实现,它将导致 JDBCException…

 @Column(name = "DESC", nullable = false)
	public String getDesc() {
		return this.desc;
	} 

解决办法

1.用方括号[]将关键字括起来。

 @Column(name = "[DESC]", nullable = false)
	public String getDesc() {
		return this.desc;
	} 

2.用双引号(")将它括起来。

 @Column(name = "\"DESC\"", nullable = false)
	public String getDesc() {
		return this.desc;
	} 

结论

同样的解决方案也可以应用于保留关键字作为表名。

hibernate keyword

Java regex 验证日期格式示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/regular-expressions/how-to-validate-date-with-regular-expression/

regex validate date format

本文展示了如何使用 regex +代码来验证日期格式,支持单个和前导零的月和日格式(1 或 01),检查一个月中的第 30 天或第 31 天,以及闰年验证。

以下是有效日期的要求。

  1. 年份格式,1900,2099 regex
  2. 月份格式,1,01,2,02… 12 regex
  3. 日格式,1,01… 31 regex
  4. 闰年 2 月 29 日。code
  5. 平年,二月二十八日。code
  6. 一个月中的 31 天–1、3、5、7、8、10、12。code
  7. 一个月的 30 天–4,6,9,11,.code
  8. yyyy-MM-dduuuu-M-d,如 2020-11-03。regex
 ((?:19|20)[0-9][0-9])-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01]) 

上述正则表达式可以实现 1、2、3 和 8 的要求。对于 4,5,6,7 的需求,我们需要手工代码检查。可接受的日期范围从1900-01-011900-1-12099-12-31

1.日期格式、年、月和日的正则表达式。

1.1 正则表达式验证年份,接受1900-2099

 (19|20)[0-9][0-9]

  # explanation
  19[0-9][0-9]  # 1900-1999
  |             # ..or
  20[0-9][0-9]  # 2000-2099 

将来,如果我们想支持以21xx开始的年份,请更新正则表达式,如下所示:

 (19|20|21)[0-9][0-9] 

1.2 验证月份的正则表达式,接受01-09(前导零)、1-9(一位数)和10,11,12

 0?[1-9]|1[012]

  # explanation
  0?[1-9]       #	01-09 or 1-9
  |             #	..or
  1[012]        #	10,11,12 

1.3 Regex 验证日,接受01-09(前导零)、1-9(个位数)、10-1920-2930-31

 0?[1-9]|[12][0-9]|3[01]

  # explanation
  0?[1-9]       #  01-09 or 1-9
  |             #  ..or
  [12][0-9]     #  10-19 or 20-29
  |             #  ..or
  3[01]         #  30, 31 

1.4 我们有用于年、月和日的正则表达式,尝试结合不同的分隔符来形成不同的日期格式。

验证日期格式dd/mm/yyyy (General)d/M/uuuu (Java date formater)的正则表达式

 # (dd)/(mm)/(yyyy)
  (0?[1-9]|[12][0-9]|3[01])/(0?[1-9]|1[012])/((?:19|20)[0-9][0-9]) 

验证日期格式yyyy-mm-dd (General)uuuu-M-d (Java date formater)的正则表达式

 # (yyyy)-(mm)-(dd)
  ((?:19|20)[0-9][0-9])-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01]) 

验证日期格式yyyy.mm.dd (General)uuuu.M.d (Java date formater)的正则表达式

 # (yyyy).(mm).(dd)
  ((?:19|20)[0-9][0-9])\\.(0?[1-9]|1[012])\\.(0?[1-9]|[12][0-9]|3[01])$ 

P.S ?:表示匹配但不捕捉。请参见下面的# 3 JavaDateValidator。

2.30 或 31 天和闰年。

现在,我们可以使用上面的正则表达式来捕获年、月和日。稍后我们将检查一个月的 30 或 31 天以及闰年。

2.1 一个月的 30 天或 31 天。

  • 12 月 1、3、5、7、8、10 有 31 天。
  • 2011 年 4 月 6 日有 30 天。
 if ((month.equals("4") || month.equals("6") || month.equals("9") ||
        month.equals("04") || month.equals("06") || month.equals("09") ||
        month.equals("11")) && day.equals("31")) {
    isValid = false;
  } 

2.2 为闰年,每年 366 天,二月有 29 天;对于一个普通的年份,一年 365 天,二月有 28 天。

 if (month.equals("2") || month.equals("02")) {
    if (day.equals("30") || day.equals("31")) {
        isValid = false;
    } else if (day.equals("29")) {  // feb 29 days? leap year checking
        if (!isLeapYear(year)) {
            isValid = false;
        }
    }
  }

  private static boolean isLeapYear(int year) {
       return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
  } 

“除了能被 100 整除的年份之外,每一个能被 4 整除的年份都是闰年,但如果能被 400 整除,这些百年就是闰年。比如 1700 年、1800 年、1900 年不是闰年,1600 年、2000 年是。”

来源:维基百科闰年

3.Java 正则表达式日期验证器

这是最终版本。

DateValidator.java

 package com.mkyong.regex.date;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DateValidatorRegex {

    // ?: match but don't capture it
    // uuuu-M-d
    private static final String DATE_PATTERN =
            "^((?:19|20)[0-9][0-9])-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])$";

    private static final Pattern pattern = Pattern.compile(DATE_PATTERN);

    public static boolean isValid(final String date) {

        boolean result = false;

        Matcher matcher = pattern.matcher(date);

        if (matcher.matches()) {

            // it is a valid date format yyyy-mm-dd
            // assign true first, later we will check the leap year and odd or even months
            result = true;

            // (?:19|20), match but don't capture it, otherwise it will messy the group order
            // for example, 2020-2-30, it will create 4 groups.
            // group(1) = 2020, group(2) matches (19|20) = 20, group(3) = 2, group(4) = 30
            // So, we put (?:19|20), don't capture this group.

            int year = Integer.parseInt(matcher.group(1));
            // why string? month matches 02 or 2
            String month = matcher.group(2);
            String day = matcher.group(3);

            // 30 or 31 days checking
            // only 1,3,5,7,8,10,12 has 31 days
            if ((month.equals("4") || month.equals("6") || month.equals("9") ||
                    month.equals("04") || month.equals("06") || month.equals("09") ||
                    month.equals("11")) && day.equals("31")) {
                result = false;
            } else if (month.equals("2") || month.equals("02")) {
                if (day.equals("30") || day.equals("31")) {
                    result = false;
                } else if (day.equals("29")) {  // leap year? feb 29 days.
                    if (!isLeapYear(year)) {
                        result = false;
                    }
                }
            }

        }

        return result;
    }

    private static boolean isLeapYear(int year) {
        return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
    }
} 

4.单元测试

下面是针对上述 Java 日期验证器的 JUnit 5 参数化测试。

DateValidatorTest.java

 package com.mkyong.regex.date;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class DateValidatorTest {

    @ParameterizedTest(name = "#{index} - Run test with date = {0}")
    @MethodSource("validDateProvider")
    void test_date_regex_valid(String date) {
        assertTrue(DateValidatorRegex.isValid(date));
    }

    @ParameterizedTest(name = "#{index} - Run test with date = {0}")
    @MethodSource("invalidDateProvider")
    void test_date_regex_invalid(String date) {
        assertFalse(DateValidatorRegex.isValid(date));
    }

    static Stream<String> validDateProvider() {
        return Stream.of(
                "1998-09-30",
                "1998-9-30",
                "2020-09-1",
                "2020-09-01",
                "2020-9-1",
                "2020-9-01",
                "2020-2-29",             // leap year
                "2020-2-28",             // leap year
                "2019-2-28",             // common year
                "2000-02-29",            // 2000 is a leap year, % 400 == 0
                "1900-02-28",            // 1900 is a common year
                "2020-07-31",
                "2020-08-31",
                "2020-06-30",
                "1900-01-01",
                "2099-12-31");
    }

    static Stream<String> invalidDateProvider() {
        return Stream.of(
                "1998-09-31",               // invalid day, sep max 30
                "1998-11-31",               // invalid day, nov max 30
                "2008-02-2x",               // invalid day 2x
                "2008-0x-28",               // invalid month 0x
                "20xx-02-28",               // invalid year 20xx
                "20-11-02",                 // invalid year 20, must be yyyy
                "2020/11/02",               // invalid date format, yyyy-mm-dd
                "2020-11-32",               // invalid day, 32
                "2020-13-30",               // invalid month 13
                "2020-A-20",                // invalid month A
                "2020-2-30",                // leap year, feb max 29
                "2019-2-29",                // common year, feb max 28
                "1900-02-29",               // 1900 is a common year, feb max 28
                "12012-04-05",              // support only 4 digits years
                " ",                        // empty
                "");                        // empty
    }

} 

所有测试都通过了。

java regex date format unit tests 1java regex date format unit tests 2

5.Java 8 datetime formatter+resolver style。严格的

对于反正则表达式开发人员,可以考虑使用 Java 8 DateTimeFormatter + ResolverStyle.STRICT解决方案来验证日期格式。关于完整的例子和单元测试,请参考本文—检查 Java 中的日期是否有效

 public static boolean isValid(final String date) {

    boolean valid = false;

    try {

        // ResolverStyle.STRICT for 30, 31 days checking, and also leap year.
        LocalDate.parse(date,
                DateTimeFormatter.ofPattern("uuuu-M-d")
                        .withResolverStyle(ResolverStyle.STRICT)
        );

        valid = true;

    } catch (DateTimeParseException e) {
        e.printStackTrace();
        valid = false;
    }

    return valid;
} 

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-regex/date

参考

Java 电子邮件正则表达式示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/regular-expressions/how-to-validate-email-address-with-regular-expression/

java email regex

一个邮件地址的格式是local-part@domain。看看这个邮件地址mkyong@example.com

  1. local-part = mkyong
  2. @ = @
  3. domain:example.com

电子邮件地址的正式定义在 RFC 5322RFC 3696 中。然而,本文不会遵循上述 RFC 进行电子邮件验证。官方邮件“local-part”太复杂(支持太多特殊字符、符号、注释、引号……)无法通过 regex 实现。大多数公司或网站选择只允许某些特殊字符,如点(。)、下划线(_)和连字符(-)。

本文将展示几种通过正则表达式验证电子邮件地址的方法:

  1. 电子邮件正则表达式–简单
  2. 电子邮件正则表达式-严格
  3. 电子邮件正则表达式–非拉丁或 Unicode 字符
  4. Apache Commons 验证 1.7 版

1.电子邮件正则表达式-简单验证。

这个例子使用一个简单的正则表达式^(.+)@(\S+)$来验证一个电子邮件地址。它检查以确保电子邮件至少包含一个字符,一个@符号,然后是一个非空白字符。

电子邮件正则表达式解释:

 ^                       #start of the line
  (                     #   start of group #1
    .+                  #     any characters (matches Unicode), must contains one or more (+)
  )                     #   end of group   #1
    @                   #     must contains a "@" symbol
      (                 #         start of group #2
        \S+             #           non white space characters, must contains one or more (+)
      )                 #         end of group #2
$                       #end of the line 

1.1 使用上述正则表达式进行电子邮件验证的 Java 示例。

EmailValidatorSimple.java

 package com.mkyong.regex.email;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class EmailValidatorSimple {

    private static final String EMAIL_PATTERN = "^(.+)@(\\S+)$";

    private static final Pattern pattern = Pattern.compile(EMAIL_PATTERN);

    public static boolean isValid(final String email) {
        Matcher matcher = pattern.matcher(email);
        return matcher.matches();
    }

} 

1.2 下面是一个 JUnit 5 单元测试,测试一些有效和无效的邮件。

EmailValidatorSimpleTest.java

 package com.mkyong.regex;

import com.mkyong.regex.email.EmailValidatorSimple;
import com.mkyong.regex.email.EmailValidatorStrict;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class EmailValidatorSimpleTest {

    @ParameterizedTest(name = "#{index} - Run test with email = {0}")
    @MethodSource("validEmailProvider")
    void test_email_valid(String email) {
        assertTrue(EmailValidatorSimple.isValid(email));
    }

    @ParameterizedTest(name = "#{index} - Run test with email = {0}")
    @MethodSource("invalidEmailProvider")
    void test_email_invalid(String email) {
        assertFalse(EmailValidatorSimple.isValid(email));
    }

    // Valid email addresses
    static Stream<String> validEmailProvider() {
        return Stream.of(
                "hello@example.com",                // simple
                "hello@example.co.uk",              // .co.uk
                "hello-.+_=#|@example.com",         // special characters
                "h@example.com",                    // local-part one letter
                "h@com",                            // domain one letter
                "我買@屋企.香港"                      // unicode, chinese characters
        );
    }

    // Invalid email addresses
    static Stream<String> invalidEmailProvider() {
        return Stream.of(
                "hello",                            // email need at least one @
                "hello@ "                           // domain cant end with space (whitespace)
        );
    }

} 

上面的电子邮件正则表达式没有检查太多,只过滤了奇怪或无效的电子邮件。此外,点匹配国际化或 Unicode 电子邮件地址。

2.电子邮件正则表达式-严格验证。

 ^(?=.{1,64}@)[A-Za-z0-9_-]+(\\.[A-Za-z0-9_-]+)*@[^-][A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})$ 

这个电子邮件正则表达式有点复杂,它满足以下电子邮件要求:

local-part

  1. 大写和小写拉丁字母 A 到 Z 和 A 到 Z
  2. 数字 0 到 9
  3. 允许点(。)、下划线(_)和连字符(-)
  4. 点(。)不是第一个或最后一个字符
  5. 点(。)不会连续出现,例如不允许出现 mkyong..yong@example.com
  6. 最多 64 个字符

在电子邮件local-part中,许多像#$%&'*+-/=?这样的特殊字符在技术上是有效的,但大多数邮件服务器或 web 应用程序并不接受所有这些字符。此电子邮件正则表达式只接受一般的点(。)、下划线(_)和连字符(-)。

domain

  1. 大写和小写拉丁字母 A 到 Z 和 A 到 Z
  2. 数字 0 到 9
  3. 连字符(-)不是第一个或最后一个字符
  4. 点(。)不是第一个或最后一个字符
  5. 点(。)不会连续出现
  6. tld 最少 2 个字符

Note
This email regex is not fully compliant with the RFC 5322 or RFC 3696. It follows some of the general guidelines on what is valid local-part and domain of an email address.

以下是有效电子邮件地址的示例。

 hello@example.com
hello@example.co.uk             // .co.uk, 2 tld
hello-2020@example.com          // -
hello.2020@example.com          // .
hello_2020@example.com          // _
h@example.com                   // local-part one letter
h@example-example.com           // domain contains a hyphen -
h@example-example-example.com   // domain contains two hyphens - -
h@example.example-example.com   // domain contains . -
hello.world-2020@example.com    // local-part contains . - 

以下是无效电子邮件地址的示例。

 hello                            // email need at least one @
hello@2020@example.com           // email doesn't allow more than one @
.hello@example.com               // local-part can't start with a dot .
hello.@example.com               // local-part can't end with a dot .
hello..world@example.com         // local part don't allow dot . appear consecutively
hello!+2020@example.com          // local-part don't allow special characters like !+
hello@example.a                  // domain tld min 2 chars
hello@example..com               // domain doesn't allow dot . appear consecutively
hello@.com                       // domain doesn't start with a dot .
hello@.com.                      // domain doesn't end with a dot .
hello@-example.com               // domain doesn't allow to start with a hyphen -
hello@example.com-               // domain doesn't allow to end with a hyphen -
hello@example_example.com        // domain doesn't allow underscore
1234567890123456789012345678901234567890123456789012345678901234xx@example.com // local part is longer than 64 characters 

再次访问电子邮件正则表达式。

 ^(?=.{1,64}@)[A-Za-z0-9_-]+(\\.[A-Za-z0-9_-]+)*@[^-][A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})$ 

电子邮件正则表达式解释。

 (?=.{1,64}@)            # local-part min 1 max 64

[A-Za-z0-9_-]+          # Start with chars in the bracket [ ], one or more (+)
                        # dot (.) not in the bracket[], it can't start with a dot (.)

(\\.[A-Za-z0-9_-]+)*	 # follow by a dot (.), then chars in the bracket [ ] one or more (+)
                        # * means this is optional
                        # this rule for two dots (.)

@                       # must contains a @ symbol

[^-]                    # domain can't start with a hyphen (-)

[A-Za-z0-9-]+           # Start with chars in the bracket [ ], one or more (+)     

(\\.[A-Za-z0-9-]+)*      # follow by a dot (.), optional

(\\.[A-Za-z]{2,})       # the last tld, chars in the bracket [ ], min 2 

2.1 使用上述正则表达式进行电子邮件验证的 Java 示例。

EmailValidatorStrict.java

 package com.mkyong.regex.email;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class EmailValidatorStrict {

    private static final String EMAIL_PATTERN =
            "^(?=.{1,64}@)[A-Za-z0-9_-]+(\\.[A-Za-z0-9_-]+)*@"
            + "[^-][A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})$";

    private static final Pattern pattern = Pattern.compile(EMAIL_PATTERN);

    public static boolean isValid(final String email) {
        Matcher matcher = pattern.matcher(email);
        return matcher.matches();
    }

} 

2.2 单元测试。

EmailValidatorStrictTest.java

 package com.mkyong.regex;

import com.mkyong.regex.email.EmailValidatorStrict;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;

public class EmailValidatorStrictTest {

    @ParameterizedTest(name = "#{index} - Run test with email = {0}")
    @MethodSource("validEmailProvider")
    void test_email_valid(String email) {
        assertTrue(EmailValidatorStrict.isValid(email));
    }

    @ParameterizedTest(name = "#{index} - Run test with email = {0}")
    @MethodSource("invalidEmailProvider")
    void test_email_invalid(String email) {
        assertFalse(EmailValidatorStrict.isValid(email));
    }

    // Valid email addresses
    static Stream<String> validEmailProvider() {
        return Stream.of(
                "hello@example.com",                // simple
                "hello@example.co.uk",              // .co.uk, 2 tld
                "hello-2020@example.com",           // -
                "hello.2020@example.com",           // .
                "hello_2020@example.com",           // _
                "h@example.com",                    // local-part one letter
                "h@example-example.com",            // domain contains a hyphen -
                "h@example-example-example.com",    // domain contains two hyphens - -
                "h@example.example-example.com",    // domain contains . -
                "hello.world-2020@example.com");    // local-part contains . -
    }

    // Invalid email addresses
    static Stream<String> invalidEmailProvider() {
        return Stream.of(
                "我買@屋企.香港",                     // this regex doesn't support Unicode
                "hello",                            // email need at least one @
                "hello@2020@example.com",           // email doesn't allow more than one @
                ".hello@example.com",               // local-part can't start with a dot .
                "hello.@example.com",               // local-part can't end with a dot .
                "hello..world@example.com",         // local part don't allow dot . appear consecutively
                "hello!+2020@example.com",          // local-part don't allow special characters like !+
                "hello@example.a",                  // domain tld min 2 chars
                "hello@example..com",               // domain doesn't allow dot . appear consecutively
                "hello@.com",                       // domain doesn't start with a dot .
                "hello@.com.",                      // domain doesn't end with a dot .
                "hello@-example.com",               // domain doesn't allow to start with a hyphen -
                "hello@example.com-",               // domain doesn't allow to end with a hyphen -
                "hello@example_example.com",        // domain doesn't allow underscore
                "1234567890123456789012345678901234567890123456789012345678901234xx@example.com"); // local part is longer than 64 characters
    }

} 

另外,如果我们想支持额外的特殊字符,比如local-part中的+=!$%|,只要把它放在方括号[] 中就可以了

 [A-Za-z0-9_-+=!$%|] 

注意
请不要对邮件验证过于严格,因为它会拒绝许多有效的邮件。这个电子邮件正则表达式严格版本很好地平衡了大多数情况下被认为是有效的电子邮件。

附:此电子邮件正则表达式严格版不支持 Unicode。

3.电子邮件正则表达式–非拉丁或 Unicode 字符

为了让 regex 支持国际化、Unicode 或非拉丁文电子邮件地址,请尝试用一个\p{L}替换字符匹配A-Za-z。阅读这个 Unicode 正则表达式

Unicode 电子邮件地址示例

 "我買@屋企.香港",                     // chinese characters
"二ノ宮@黒川.日本",                   // Japanese characters 

下面的 regex 更新了以前的电子邮件 regex strict 版本,将A-Za-z替换为\\p{L},以支持 Unicode 电子邮件地址。

 ^(?=.{1,64}@)[\\p{L}0-9_-]+(\\.[\\p{L}0-9_-]+)*@[^-][\\p{L}0-9-]+(\\.[\\p{L}0-9-]+)*(\\.[\\p{L}]{2,})$ 

3.1 Java 电子邮件正则表达式验证,Unicode 版本。

EmailValidatorUnicode.java

 package com.mkyong.regex.email;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class EmailValidatorUnicode {

    private static final String EMAIL_PATTERN =
            "^(?=.{1,64}@)[\\p{L}0-9_-]+(\\.[\\p{L}0-9_-]+)*@"
            + "[^-][\\p{L}0-9-]+(\\.[\\p{L}0-9-]+)*(\\.[\\p{L}]{2,})$";

    private static final Pattern pattern = Pattern.compile(EMAIL_PATTERN);

    public static boolean isValid(final String email) {
        Matcher matcher = pattern.matcher(email);
        return matcher.matches();
    }

} 

3.2 单元测试。

 @ParameterizedTest(name = "#{index} - Run test with email = {0}")
  @MethodSource("validEmailProvider")
  void test_email_valid(String email) {
      assertTrue(EmailValidatorUnicode.isValid(email));
  }

  // Valid email addresses
  static Stream<String> validEmailProvider() {
      return Stream.of(
              "hello@example.com",                // simple
              "hello@example.co.uk",              // .co.uk, 2 tld
              "hello-2020@example.com",           // -
              "hello.2020@example.com",           // .
              "hello_2020@example.com",           // _
              "h@example.com",                    // local-part one letter
              "h@example-example.com",            // domain contains a hyphen -
              "h@example-example-example.com",    // domain contains two hyphens - -
              "h@example.example-example.com",    // domain contains . -
              "hello.world-2020@example.com",     // local part contains . -
              "我買@屋企.香港",                     // chinese characters
              "二ノ宮@黒川.日本",                    // Japanese characters
              "δοκιμή@παράδειγμα.δοκιμή");        // Greek alphabet
  } 

4.Apache Commons 验证程序-电子邮件

这一次我们测试了 Apache Commons Validator 来验证一个电子邮件地址。

pom.xml

 <dependency>
      <groupId>commons-validator</groupId>
      <artifactId>commons-validator</artifactId>
      <version>1.7</version>
  </dependency> 

P . Scommons-validator-1.7.jar的文件大小在 190KB 左右。

在内部,commons-validator混合使用自定义代码和正则表达式来验证电子邮件地址。

EmailValidator.java

 package org.apache.commons.validator.routines;

public class EmailValidator implements Serializable {

    //...

    public boolean isValid(String email) {
        if (email == null) {
            return false;
        }

        if (email.endsWith(".")) { // check this first - it's cheap!
            return false;
        }

        // Check the whole email address structure
        Matcher emailMatcher = EMAIL_PATTERN.matcher(email);
        if (!emailMatcher.matches()) {
            return false;
        }

        if (!isValidUser(emailMatcher.group(1))) {
            return false;
        }

        if (!isValidDomain(emailMatcher.group(2))) {
            return false;
        }

        return true;
    }

} 

4.1 使用 Apache Commons 验证器的 Java 电子邮件验证。

EmailValidatorApache.java

 package com.mkyong.regex.email;

import org.apache.commons.validator.routines.EmailValidator;

public class EmailValidatorApache {

    //doesn't consider local addresses as valid.
    //default, allowLocal = false, allowTld = false
    private static final EmailValidator validator = EmailValidator.getInstance();

    //private static final EmailValidator validator = EmailValidator.getInstance(true);
    //private static final EmailValidator validator = EmailValidator.getInstance(true, true);

    public static boolean isValid(final String email) {
        return validator.isValid(email);
    }

} 

4.2 单元测试。

EmailValidatorApacheTest.java

 package com.mkyong.regex;

import com.mkyong.regex.email.EmailValidatorApache;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class EmailValidatorApacheTest {

    @ParameterizedTest(name = "#{index} - Run test with email = {0}")
    @MethodSource("validEmailProvider")
    void test_email_valid(String email) {
        assertTrue(EmailValidatorApache.isValid(email));
    }

    @ParameterizedTest(name = "#{index} - Run test with email = {0}")
    @MethodSource("invalidEmailProvider")
    void test_email_invalid(String email) {
        assertFalse(EmailValidatorApache.isValid(email));
    }

    // Valid email addresses
    static Stream<String> validEmailProvider() {
        return Stream.of(
                "hello@example.com",                // simple
                "hello@example.co.uk",              // .co.uk, 2 tld
                "hello!#$%&'*+-/=?^_`{|}~2020@example.com",  // many special chars
                "h@example.com",                    // local-part one letter
                "h@example-example.com",            // domain contains a hyphen -
                "h@example-example-example.com",    // domain contains two hyphens - -
                "h@example.example-example.com",    // domain contains . -
                "hello.world-2020@example.com",     // local part contains . -
                "我買@屋企.香港");                   // Support Unicode
    }

    // Invalid email addresses
    static Stream<String> invalidEmailProvider() {
        return Stream.of(

                "hello",                            // email need at least one @
                "hello@2020@example.com",           // email don't allow more than one @
                ".hello@example.com",               // local-part can't start with a dot .
                "hello.@example.com",               // local-part can't end with a dot .
                "hello..world@example.com",         // local part don't allow dot . appear consecutively
                // apache supports many special characters
                //"hello!+2020@example.com",          // local-part don't allow special characters like !+
                "hello@example.a",                  // domain tld min 2 chars
                "hello@example..com",               // domain part don't allow dot . appear consecutively
                "hello@.com",                       // domain part don't start with a dot .
                "hello@.com.",                      // domain part don't end with a dot .
                "hello@-example.com",               // domain part don't allow to start with a hyphen -
                "hello@example.com-",               // domain part don't allow to end with a hyphen -
                "hello@example_example.com",        // domain part don't allow underscore
                "1234567890123456789012345678901234567890123456789012345678901234xx@example.com"); // local part is longer than 64 characters
    }

} 

比较上述电子邮件正则表达式严格版。这个commons-validator支持许多特殊字符,如!#$%&'*+-/=?^_{|}~,甚至是 Unicode 字符,并且符合示例 2 中定义的通用电子邮件准则。如果你不介意包含一个额外的 190KB 的库来验证电子邮件,这个commons-validator是一个不错的选择。

commons-validator不完全符合 RFC 5322RFC 3696

如果你对 RFC822 电子邮件正则表达式感兴趣,请访问这个 RFC822:基于正则表达式的地址验证

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-regex/email

参考

Java 正则表达式十六进制颜色代码

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/regular-expressions/how-to-validate-hex-color-code-with-regular-expression/

这篇文章展示了如何使用正则表达式来验证一个十六进制的颜色代码。

十六进制颜色代码的正则表达式。

 ^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$ 

正则表达式解释

 ^                 # start of the line
  #                 # start with a number sign `#`
  (                 # start of (group 1)
    [a-fA-F0-9]{6}  # support z-f, A-F and 0-9, with a length of 6
    |               # or
    [a-fA-F0-9]{3}  # support z-f, A-F and 0-9, with a length of 3
  )                 # end of (group 1)
  $                 # end of the line 

1.十六进制颜色代码格式。

在 web 中,我们可以使用 RGB 三元组或十六进制三元组(十六进制颜色代码)来表示网页上的颜色。对于十六进制颜色代码,有两种格式,标准十六进制三联体和简写十六进制格式,两种格式都以前导数字符号#开始。

1.1 十六进制三联体格式
十六进制三联体或标准十六进制色码使用六位(十六进制)数字形式来表示颜色。例如:

 #000000
  #FFFFFF
  #808080
  #8A2BE2 

对于#8A2BE2,第一个十六进制8A代表红色值,第二个2B代表绿色值,第三个E2代表蓝色值。

1.2 速记十六进制格式
速记十六进制使用三位(十六进制)数字形式来表示一种颜色。这个想法仅仅是将每个数字加倍,成为上面的十六进制三联体格式。例如:

 #000
  #FFF
  #09C 

对于#000,会变成#000000。对于#09C,就变成了#0099CC

阅读下面的 CSS 语法;两者代表相同的颜色。

 p   { color: #000;    }   /* black color, hex triplet format */
  h1  { color: #000000; }   /* same color as above, shorthand hex format */ 

网页颜色
更多信息,请阅读此维基百科-网页颜色

2.验证十六进制颜色代码的 Java 正则表达式

下面是一个 Java regex 示例,用于验证标准十六进制三元组和简写格式的十六进制颜色代码。

HexValidatorWebColor.java

 package com.mkyong.regex.hex;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class HexValidatorWebColor {

    private static final String HEX_WEBCOLOR_PATTERN
            = "^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$";

    private static final Pattern pattern = Pattern.compile(HEX_WEBCOLOR_PATTERN);

    public static boolean isValid(final String colorCode) {
        Matcher matcher = pattern.matcher(colorCode);
        return matcher.matches();
    }

} 

3.测试 regex 十六进制颜色代码。

下面是验证有效和无效十六进制颜色代码列表的单元测试。

HexValidatorWebColorTest.java

 package com.mkyong.regex.hex;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class HexValidatorWebColorTest {

    @ParameterizedTest(name = "#{index} - Run test with web color = {0}")
    @MethodSource("validWebColorProvider")
    void test_color_regex_valid(String color) {
        assertTrue(HexValidatorWebColor.isValid(color));
    }

    @ParameterizedTest(name = "#{index} - Run test with web color = {0}")
    @MethodSource("invalidWebColorProvider")
    void test_color_regex_invalid(String color) {
        assertFalse(HexValidatorWebColor.isValid(color));
    }

    static Stream<String> validWebColorProvider() {
        return Stream.of(
                "#000000",
                "#999999",
                "#1a1a1a",
                "#1A1A1A",
                "#0f0f0f",
                "#0F0F0F",
                "#bcbcbc",
                "#BcbCbC",
                "#000",
                "#FFF",
                "#abc",
                "#def");
    }

    static Stream<String> invalidWebColorProvider() {
        return Stream.of(
                "123456",                   // must start with a #
                "#afafah",                  // support a-f only, h is not allowed
                "#123abce",                 // invalid length, must length of 3 or 6
                "#1234",                    // invalid length, must length of 3 or 6
                "#-123",                    // support 0-9 only
                " ",                        // space
                "");                        // empty
    }

} 

4.从字符串中查找十六进制颜色代码

下面是一个使用正则表达式从字符串中查找或提取十六进制颜色代码的例子。

FindHexColorCode.java

 package com.mkyong.regex.hex;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class FindHexColorCode {

    public static void main(String[] args) {

        String str = "p { color: #000; }";

        Pattern pattern = Pattern.compile(
                "^(.*?)(#([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))\\b(.*)$");

        Matcher matcher = pattern.matcher(str);
        if (matcher.matches()) {
            System.out.println(matcher.groupCount());     // 4
            System.out.println(matcher.group(0));         // p { color: #000; }
            System.out.println(matcher.group(1));         // p { color:
            System.out.println(matcher.group(2));         // #000
            System.out.println(matcher.group(3));         // 000
            System.out.println(matcher.group(4));         // ; }
        } else {
            System.out.println("no match!");
        }

    }

} 

输出

Terminal

 4
p { color: #000; }
p { color:
#000
000
; } 

在 regex 中,\b元字符意味着单词边界,这确保十六进制颜色代码后面没有任何单词。

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-regex/hex

参考

如何用正则表达式验证 HTML 标签

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/regular-expressions/how-to-validate-html-tag-with-regular-expression/

HTML 标记正则表达式模式

 <("[^"]*"|'[^']*'|[^'">])*> 

描述

 <	  	#start with opening tag "<"
 (		#   start of group #1
   "[^"]*"	#	allow string with double quotes enclosed - "string"
   |		#	..or
   '[^']*'	#	allow string with single quote enclosed - 'string'
   |		#	..or
   [^'">]	#	cant contains one single quotes, double quotes and ">"
 )		#   end of group #1
 *		# 0 or more
>		#end with closing tag ">" 

HTML 标签,以开始标签"开始,不带单引号或双引号。最后,以结束标记“>”结束

Java 正则表达式示例

 package com.mkyong.regex;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class HTMLTagValidator{

   private Pattern pattern;
   private Matcher matcher;

   private static final String HTML_TAG_PATTERN = "<(\"[^\"]*\"|'[^']*'|[^'\">])*>";

   public HTMLTagValidator(){
	  pattern = Pattern.compile(HTML_TAG_PATTERN);
   }

  /**
   * Validate html tag with regular expression
   * @param tag html tag for validation
   * @return true valid html tag, false invalid html tag
   */
  public boolean validate(final String tag){

	  matcher = pattern.matcher(tag);
	  return matcher.matches();

  }
} 

匹配 HTML 标签:

1.' >
二<输入值=' < ' >","< b/ > "
3。"
4< br >,

5。"<输入值="" id='test' >","<输入值=" id='test' >"

HTML 标记不匹配:

1.""–不允许使用一个双引号字符串
2。"<输入值= ' id = ' test '>"–不允许使用单引号字符串
3。"<输入值=>>"–不允许单引号>,必须用单引号或双引号括起来

单元测试–HTMLTagValidatorTest

 package com.mkyong.regex;

import org.testng.Assert;
import org.testng.annotations.*;

/**
 * HTMLTag validator Testing
 * @author mkyong
 *
 */
public class HTMLTagValidatorTest {

	private HTMLTagValidator htmlTagValidator;

	@BeforeClass
        public void initData(){
		htmlTagValidator = new HTMLTagValidator();
        }

	@DataProvider
	public Object[][] ValidHTMLTagProvider() {
    	   return new Object[][]{
		   new Object[] {"<b>"}, 
                   new Object[] {"<input value='>'>"},
		   new Object[] {"<input value='<'>"}, 
		   new Object[] {"<b/>"},
                   new Object[] {"<a href='http://www.google.com'>"},
		   new Object[] {"<br>"},
                   new Object[] {"<br/>"},
		   new Object[] {"<input value=\"\" id='test'>"},
                   new Object[] {"<input value='' id='test'>"}
	   };
	}

	@DataProvider
	public Object[][] InvalidHTMLTagProvider() {
	    return new Object[][]{
		  new Object[] {"<input value=\" id='test'>"},
	  	  new Object[] {"<input value=' id='test'>"},
	  	  new Object[] {"<input value=> >"}
	    };
	}

	@Test(dataProvider = "ValidHTMLTagProvider")
	public void ValidHTMLTagTest(String tag) {

	    boolean valid = htmlTagValidator.validate(tag);
	    System.out.println("HTMLTag is valid : " + tag + " , " + valid);
	    Assert.assertEquals(true, valid);

	}

	@Test(dataProvider = "InvalidHTMLTagProvider", 
                 dependsOnMethods="ValidHTMLTagTest")
	public void InValidHTMLTagTest(String tag) {

	   boolean valid = htmlTagValidator.validate(tag);
	   System.out.println("HTMLTag is valid : " + tag + " , " + valid);
	   Assert.assertEquals(false, valid);

	}
} 

单元测试–结果

 HTMLTag is valid : <b> , true
HTMLTag is valid : <input value='>'> , true
HTMLTag is valid : <input value='<'> , true
HTMLTag is valid : <b/> , true
HTMLTag is valid : <a href='http://www.google.com'> , true
HTMLTag is valid : <br> , true
HTMLTag is valid : <br/> , true
HTMLTag is valid : <input value="" id='test'> , true
HTMLTag is valid : <input value='' id='test'> , true
HTMLTag is valid : <input value=" id='test'> , false
HTMLTag is valid : <input value=' id='test'> , false
HTMLTag is valid : <input value=> > , false
PASSED: ValidHTMLTagTest("<b>")
PASSED: ValidHTMLTagTest("<input value='>'>")
PASSED: ValidHTMLTagTest("<input value='<'>")
PASSED: ValidHTMLTagTest("<b/>")
PASSED: ValidHTMLTagTest("<a href='http://www.google.com'>")
PASSED: ValidHTMLTagTest("<br>")
PASSED: ValidHTMLTagTest("<br/>")
PASSED: ValidHTMLTagTest("<input value="" id='test'>")
PASSED: ValidHTMLTagTest("<input value='' id='test'>")
PASSED: InValidHTMLTagTest("<input value=" id='test'>")
PASSED: InValidHTMLTagTest("<input value=' id='test'>")
PASSED: InValidHTMLTagTest("<input value=> >")

===============================================
    com.mkyong.regex.HTMLTagValidatorTest
    Tests run: 12, Failures: 0, Skips: 0
===============================================

===============================================
mkyong
Total tests run: 12, Failures: 0, Skips: 0
=============================================== 

想了解更多关于正则表达式的知识吗?强烈推荐这本最好最经典的书——《掌握正则表达式》

http://web.archive.org/web/20190310100540if_/http://rcm.amazon.com/e/cm?t=progrlife-20&o=1&p=8&l=as1&asins=0596528124&fc1=000000&IS2=1&lt1=_blank&m=amazon&lc1=0000FF&bc1=000000&bg1=FFFFFF&f=ifr

html regex

如何用正则表达式验证图像文件扩展名

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/regular-expressions/how-to-validate-image-file-extension-with-regular-expression/

图像文件扩展名正则表达式模式

 ([^\s]+(\.(?i)(jpg|png|gif|bmp))$) 

描述

 (			#Start of the group #1
 [^\s]+			#  must contains one or more anything (except white space)
       (		#    start of the group #2
         \.		#	follow by a dot "."
         (?i)		#	ignore the case sensive checking for the following characters
             (		#	  start of the group #3
              jpg	#	    contains characters "jpg"
              |		#	    ..or
              png	#	    contains characters "png"
              |		#	    ..or
              gif	#	    contains characters "gif"
              |		#	    ..or
              bmp	#	    contains characters "bmp"
             )		#	  end of the group #3
       )		#     end of the group #2	
  $			#  end of the string
)			#end of the group #1 

整个组合是指,必须有一个或多个字符串(但不是空白),后跟点“.”并且字符串以“jpg”或“png”或“gif”或“bmp”结尾,文件扩展名不区分大小写。

这种正则表达式模式广泛用于不同文件广泛检查。您只需改变结尾组合 (jpg|png|gif|bmp) 就可以得到适合您需要的不同文件扩展名检查。

Java 正则表达式示例

 package com.mkyong.regex;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ImageValidator{

   private Pattern pattern;
   private Matcher matcher;

   private static final String IMAGE_PATTERN = 
                "([^\\s]+(\\.(?i)(jpg|png|gif|bmp))$)";

   public ImageValidator(){
	  pattern = Pattern.compile(IMAGE_PATTERN);
   }

   /**
   * Validate image with regular expression
   * @param image image for validation
   * @return true valid image, false invalid image
   */
   public boolean validate(final String image){

	  matcher = pattern.matcher(image);
	  return matcher.matches();

   }
} 

匹配的图像文件:

1." a.jpg "," a.gif "," a.png "," a.bmp ",
2。"..jpg ","..gif ","..png ","..bmp”,
3。“a.JPG”,“a.GIF”,“a.PNG”,“a.BMP”,
4。" a.JpG "," a.GiF "," a.PnG "," a.BmP ",
5。" jpg.jpg "," gif.gif "," png.png "," bmp.bmp "

不匹配的图像:

1.".jpg“,”。gif“,”。png“,”。BMP”-需要图像文件名
2。" .jpg“,”。gif“,”。png“,”。BMP”-第一个字符
3 中不允许有空格。" a.txt "," a.exe "," a . "," a . MP3 "-只允许图像文件扩展名为
3。"jpg "," gif "," png "," BMP "-需要图像文件扩展名

单元测试–image validator

 package com.mkyong.regex;

import org.testng.Assert;
import org.testng.annotations.*;

/**
 * Image validator Testing
 * @author mkyong
 *
 */
public class ImageValidatorTest {

	private ImageValidator imageValidator;

	@BeforeClass
        public void initData(){
		imageValidator = new ImageValidator();
        }

	@DataProvider
	public Object[][] ValidImageProvider() {
	   return new Object[][]{
    	     {new String[] {
		   "a.jpg", "a.gif","a.png", "a.bmp",
		   "..jpg", "..gif","..png", "..bmp",
		   "a.JPG", "a.GIF","a.PNG", "a.BMP",
		   "a.JpG", "a.GiF","a.PnG", "a.BmP",
		   "jpg.jpg", "gif.gif","png.png", "bmp.bmp"
  	       }
              }
	   };
	}

	@DataProvider
	public Object[][] InvalidImageProvider() {
	  return new Object[][]{
	    {new String[] {
		   ".jpg", ".gif",".png",".bmp",
		   " .jpg", " .gif"," .png"," .bmp",
                   "a.txt", "a.exe","a.","a.mp3",
		   "jpg", "gif","png","bmp"
	       }
             }
	   };
	}

	@Test(dataProvider = "ValidImageProvider")
	 public void ValidImageTest(String[] Image) {

	   for(String temp : Image){
		   boolean valid = imageValidator.validate(temp);
		   System.out.println("Image is valid : " + temp + " , " + valid);
		   Assert.assertEquals(true, valid);
	   }

	}

	@Test(dataProvider = "InvalidImageProvider", 
                 dependsOnMethods="ValidImageTest")
	public void InValidImageTest(String[] Image) {

	   for(String temp : Image){
		   boolean valid = imageValidator.validate(temp);
		   System.out.println("Image is valid : " + temp + " , " + valid);
		   Assert.assertEquals(false, valid);
	   }
	}	
} 

单元测试–结果

 Image is valid : a.jpg , true
Image is valid : a.gif , true
Image is valid : a.png , true
Image is valid : a.bmp , true
Image is valid : ..jpg , true
Image is valid : ..gif , true
Image is valid : ..png , true
Image is valid : ..bmp , true
Image is valid : a.JPG , true
Image is valid : a.GIF , true
Image is valid : a.PNG , true
Image is valid : a.BMP , true
Image is valid : a.JpG , true
Image is valid : a.GiF , true
Image is valid : a.PnG , true
Image is valid : a.BmP , true
Image is valid : jpg.jpg , true
Image is valid : gif.gif , true
Image is valid : png.png , true
Image is valid : bmp.bmp , true
Image is valid : .jpg , false
Image is valid : .gif , false
Image is valid : .png , false
Image is valid : .bmp , false
Image is valid :  .jpg , false
Image is valid :  .gif , false
Image is valid :  .png , false
Image is valid :  .bmp , false
Image is valid : a.txt , false
Image is valid : a.exe , false
Image is valid : a. , false
Image is valid : a.mp3 , false
Image is valid : jpg , false
Image is valid : gif , false
Image is valid : png , false
Image is valid : bmp , false
PASSED: ValidImageTest([Ljava.lang.String;@1d4c61c)
PASSED: InValidImageTest([Ljava.lang.String;@116471f)

===============================================
    com.mkyong.regex.ImageValidatorTest
    Tests run: 2, Failures: 0, Skips: 0
===============================================

===============================================
mkyong
Total tests run: 2, Failures: 0, Skips: 0
=============================================== 

想了解更多关于正则表达式的知识吗?强烈推荐这本最好最经典的书——《掌握正则表达式》

http://web.archive.org/web/20221227014350if_/https://rcm.amazon.com/e/cm?t=progrlife-20&o=1&p=8&l=as1&asins=0596528124&fc1=000000&IS2=1&lt1=_blank&m=amazon&lc1=0000FF&bc1=000000&bg1=FFFFFF&f=ifr

Java IP 地址(IPv4)正则表达式示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/regular-expressions/how-to-validate-ip-address-with-regular-expression/

ipv4 regex

本文主要讨论如何使用 regex 和 Apache Commons Validator 来验证 IP 地址( IPv4 )。

这是总结。

  1. IPv4 正则表达式解释。
  2. Java IPv4 验证器,使用正则表达式。
  3. Java IPv4 验证器,使用commons-validator-1.7
  4. 针对上述 IPv4 验证器的 JUnit 5 单元测试。

IPv4 正则表达式最终版本。

 ^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.(?!$)|$)){4}$ 
 # Explanation
(
  [0-9]         # 0-9
  |             # or
  [1-9][0-9]    # 10-99
  |             # or
  1[0-9][0-9]   # 100-199
  |             # or
  2[0-4][0-9]   # 200-249
  |             # or
  25[0-5]       # 250-255
)
(\.(?!$)|$))    # ensure IPv4 doesn't end with a dot
{4}             # 4 times. 

此正则表达式仅适用于 IPv4 地址。它不支持 IPv4 子网或 IPv6。

1.IPv4 正则表达式解释。

有效的 IPv4 范围是从0.0.0.0255.255.255.255,我们需要创建一个正则表达式来确保范围[0-255]中的数字和点在正确的位置。

下面的 1.1 是第一个 IPv4 正则表达式。以后我们会把它进化成更好更短的版本。

 // version 1 allow leading zero, 01.01.01.01
  private static final String IPV4_PATTERN_ALLOW_LEADING_ZERO =
            "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
            "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
            "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
            "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$"; 

1.2 上面的正则表达式使用\\d来匹配数字0-9。然而,\\d也将匹配 Unicode 数字;出于安全原因,请使用[0-9]仅匹配 ASCII 码。

下面是 IPv4 正则表达式版本 2。

 // version 2 , allow leading zero, 01.01.01.01
  private static final String IPV4_PATTERN_ALLOW_LEADING_ZERO =
            "^([01]?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\\." +
            "([01]?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\\." +
            "([01]?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\\." +
            "([01]?[0-9][0-9]?|2[0-4][0-9]|25[0-5])$"; 

下面是对上述正则表达式的解释。

 ^                       #  start of the line
  (                     #  start of group #1
    [01]?[0-9][0-9]?    #  can be one or two digits. If three digits appear, it must start either 0 or 1
    |                   #    ...or
    2[0-4][0-9]         #    start with 2, follow by 0-4 and end with any digit (2[0-4][0-9])
    |                   #    ...or
    25[0-5]             #    start with 2, follow by 5 and ends with 0-5 (25[0-5])
  )                     #  end of group  #1
  \\.                   #  follow by a dot "."
                        # repeat it 3 times (3x)
$                       # end of the line 

1.3 但是,版本 1 和版本 2 支持 IPv4 地址中的前导零,例如01.01.01.01。前导零是有效的 IPv4 地址吗?

下面是 IPv4 regex 版本 3;它不允许在 IPv4 地址中使用前导零。

 // version 3, simple and easy to understand
  private static final String IPV4_PATTERN =
           "^([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\." +
           "([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\." +
           "([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\." +
           "([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$"; 

下面是对上述正则表达式的解释;这是一个冗长乏味的正则表达式,但是可读性很强,非常容易理解。

 (
  [0-9]         # 0-9
  |             # or
  [1-9][0-9]    # 10-99
  |             # or
  1[0-9][0-9]   # 100-199
  |             # or
  2[0-4][0-9]   # 200-249
  |             # or
  25[0-5]       # 250-255
)
\\.             # follow by a dot
                # repeat 3 times. 

下面的 1.4 是 IPv4 regex 版本 4;它的工作方式和上面的版本 3 一样,只是 regex 和 repeat {3}稍微短了一点。

 // version 4
  private static final String IPV4_PATTERN =
            "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}" +
            "([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$" 

下面的 1.5 是 IPv4 regex 版本 5,一个最终版本。它的工作原理与第 3 版和第 4 版相同,但更短,并且额外增加了(\\.(?!$)|$)以确保 IPv4 不以点结束。

 //version 5
  private static final String IPV4_PATTERN =
            "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\\.(?!$)|$)){4}$"; 


请参考下面的#4 单元测试,获取有效和无效 IPv4 地址的列表。

Extra
下面是一个短得多的 IPv4 regex 版本,仅供参考。不过我还是比较喜欢上面的 IPv4 regex 最终版 3 和版本 5。

 // 25[0-5]        = 250-255
  // (2[0-4])[0-9]  = 200-249
  // (1[0-9])[0-9]  = 100-199
  // ([1-9])[0-9]   = 10-99
  // [0-9]          = 0-9
  // (\.(?!$))      = can't end with a dot
  private static final String IPV4_PATTERN_SHORTEST =
          "^((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])(\\.(?!$)|$)){4}$"; 

请不要使用你不了解的正则表达式。

2.Java IPv4 正则表达式验证器

下面是一个 Java IPv4 正则表达式验证器的例子。它使用上述 IPv4 regex 版本 5 来验证 IPv4 地址。

IPv4ValidatorRegex.java

 package com.mkyong.regex.ipv4;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class IPv4ValidatorRegex {

    private static final String IPV4_PATTERN =
            "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\\.(?!$)|$)){4}$";

    private static final Pattern pattern = Pattern.compile(IPV4_PATTERN);

    public static boolean isValid(final String email) {
        Matcher matcher = pattern.matcher(email);
        return matcher.matches();
    }

} 

3.IPv4 验证器–Apache Commons 验证器

这个例子使用 Apache Commons 验证器来验证 IPv4 地址。

pom.xml

 <dependency>
      <groupId>commons-validator</groupId>
      <artifactId>commons-validator</artifactId>
      <version>1.7</version>
  </dependency> 

下面是另一个 Java IPv4 验证器,使用commons-validatorAPI 来验证 IPv4 地址。

IPv4ValidatorApache.java

 package com.mkyong.regex.ipv4;

import org.apache.commons.validator.routines.InetAddressValidator;

public class IPv4ValidatorApache {

    private static final InetAddressValidator validator
                              = InetAddressValidator.getInstance();

    public static boolean isValid(final String ip) {

        // only IPv4
        return validator.isValidInet4Address(ip);

        // IPv4 + IPv6
        // return validator.isValid(ip);

        // IPv6 only
        // return validator.isValidInet6Address(ip);
    }

} 

在内部,InetAddressValidator使用简单的正则表达式和手动检查来验证 IPv4 地址。

InetAddressValidator.java

 public class InetAddressValidator implements Serializable {

  private static final String IPV4_REGEX =
              "^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$";

  //...

  public boolean isValidInet4Address(String inet4Address) {
      // verify that address conforms to generic IPv4 format
      String[] groups = ipv4Validator.match(inet4Address);

      if (groups == null) {
          return false;
      }

      // verify that address subgroups are legal
      for (String ipSegment : groups) {
          if (ipSegment == null || ipSegment.length() == 0) {
              return false;
          }

          int iIpSegment = 0;

          try {
              iIpSegment = Integer.parseInt(ipSegment);
          } catch(NumberFormatException e) {
              return false;
          }

          if (iIpSegment > IPV4_MAX_OCTET_VALUE) {
              return false;
          }

          if (ipSegment.length() > 1 && ipSegment.startsWith("0")) {
              return false;
          }

      }

      return true;
  } 

4.单元测试(JUnit 5)

下面是针对上述 Java 验证器的 JUnit 5 参数化测试——2 号 IPv4 正则表达式验证器和 3 号 Apache Commons 验证器。

pom.xml

 <!-- JUnit 5 -->
  <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-params</artifactId>
      <version>5.4.0</version>
      <scope>test</scope>
  </dependency> 

IPv4ValidatorTest.java

 package com.mkyong.regex.ipv4;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class IPv4ValidatorTest {

    @ParameterizedTest(name = "#{index} - Run test with IPv4 = {0}")
    @MethodSource("validIPv4Provider")
    void test_ipv4_apache_valid(String ipv4) {
        assertTrue(IPv4ValidatorApache.isValid(ipv4));
    }

    @ParameterizedTest(name = "#{index} - Run test with IPv4 = {0}")
    @MethodSource("invalidIPv4Provider")
    void test_ipv4_apache_invalid(String ipv4) {
        assertFalse(IPv4ValidatorApache.isValid(ipv4));
    }

    @ParameterizedTest(name = "#{index} - Run test with IPv4 = {0}")
    @MethodSource("validIPv4Provider")
    void test_ipv4_regex_valid(String ipv4) {
        assertTrue(IPv4ValidatorRegex.isValid(ipv4));
    }

    @ParameterizedTest(name = "#{index} - Run test with IPv4 = {0}")
    @MethodSource("invalidIPv4Provider")
    void test_ipv4_regex_invalid(String ipv4) {
        assertFalse(IPv4ValidatorRegex.isValid(ipv4));
    }

    static Stream<String> validIPv4Provider() {
        return Stream.of(
                "0.0.0.0",
                "0.0.0.1",
                "127.0.0.1",
                "1.2.3.4",              // 0-9
                "11.1.1.0",             // 10-99
                "101.1.1.0",            // 100-199
                "201.1.1.0",            // 200-249
                "255.255.255.255",      // 250-255
                "192.168.1.1",
                "192.168.1.255",
                "100.100.100.100");
    }

    static Stream<String> invalidIPv4Provider() {
        return Stream.of(
                "000.000.000.000",          // leading 0
                "00.00.00.00",              // leading 0
                "1.2.3.04",                 // leading 0
                "1.02.03.4",                // leading 0
                "1.2",                      // 1 dot
                "1.2.3",                    // 2 dots
                "1.2.3.4.5",                // 4 dots
                "192.168.1.1.1",            // 4 dots
                "256.1.1.1",                // 256
                "1.256.1.1",                // 256
                "1.1.256.1",                // 256
                "1.1.1.256",                // 256
                "-100.1.1.1",               // -100
                "1.-100.1.1",               // -100
                "1.1.-100.1",               // -100
                "1.1.1.-100",               // -100
                "1...1",                    // empty between .
                "1..1",                     // empty between .
                "1.1.1.1.",                 // last .
                "");                        // empty
    }

} 

所有单元测试都通过了。

unit tests for ipv4 validators

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-regex/ipv4

参考

Java regex 验证密码示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/regular-expressions/how-to-validate-password-with-regular-expression/

Java regex password

本文展示了如何使用 regex 在 Java 中验证密码。

安全密码要求

  1. 密码必须包含至少一个数字[0-9]。
  2. 密码必须包含至少一个小写拉丁字符[a-z]。
  3. 密码必须包含至少一个大写拉丁字符[A-Z]。
  4. 密码必须包含至少一个特殊字符,如! @ # & ( )
  5. 密码必须包含至少 8 个字符,最多 20 个字符。

下面是符合上述所有要求的正则表达式。

 ^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#&()–[{}]:;',?/*~$^+=<>]).{8,20}$ 

1.正则表达式密码解释

密码必须包含至少一个小写字符、一个大写字符、一个数字、一个特殊字符,长度在 8 到 20 之间。下面的正则表达式使用正向前瞻进行条件检查。

 ^                                   # start of line
  (?=.*[0-9])                       # positive lookahead, digit [0-9]
  (?=.*[a-z])                       # positive lookahead, one lowercase character [a-z]
  (?=.*[A-Z])                       # positive lookahead, one uppercase character [A-Z]
  (?=.*[!@#&()–[{}]:;',?/*~$^+=<>]) # positive lookahead, one of the special character in this [..]
  .                                 # matches anything
  {8,20}                            # length at least 8 characters and maximum of 20 characters
$                                   # end of line 

在 regex 中,有正前瞻(?=)和负前瞻(?!):

  • 积极的前瞻(?=)确保某事followed by某事。
  • 消极的前瞻(?!)确保了某些东西NOT followed by某些别的东西。

例如,b(?=c)匹配后面跟有cb。(正向前瞻)
例如,b(?!c)匹配后面没有cb。(消极前瞻)

2.验证密码的正则表达式

下面是一个验证密码的 Java regex 示例。

PasswordValidator.java

 package com.mkyong.regex.password;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class PasswordValidator {

    // digit + lowercase char + uppercase char + punctuation + symbol
    private static final String PASSWORD_PATTERN =
            "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#&()–[{}]:;',?/*~$^+=<>]).{8,20}$";

    private static final Pattern pattern = Pattern.compile(PASSWORD_PATTERN);

    public static boolean isValid(final String password) {
        Matcher matcher = pattern.matcher(password);
        return matcher.matches();
    }

} 

3.正则表达式密码单元测试

下面是测试有效和无效密码列表的单元测试。

PasswordValidatorTest.java

 package com.mkyong.regex.password;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class PasswordValidatorTest {

    @ParameterizedTest(name = "#{index} - Run test with password = {0}")
    @MethodSource("validPasswordProvider")
    void test_password_regex_valid(String password) {
        assertTrue(PasswordValidator.isValid(password));
    }

    @ParameterizedTest(name = "#{index} - Run test with password = {0}")
    @MethodSource("invalidPasswordProvider")
    void test_password_regex_invalid(String password) {
        assertFalse(PasswordValidator.isValid(password));
    }

    static Stream<String> validPasswordProvider() {
        return Stream.of(
                "AAAbbbccc@123",
                "Hello world$123",
                "A!@#&()–a1",               // test punctuation part 1
                "A[{}]:;',?/*a1",           // test punctuation part 2
                "A~$^+=<>a1",               // test symbols
                "0123456789$abcdefgAB",     // test 20 chars
                "123Aa$Aa"                  // test 8 chars
        );
    }

    // At least
    // one lowercase character,
    // one uppercase character,
    // one digit,
    // one special character
    // and length between 8 to 20.
    static Stream<String> invalidPasswordProvider() {
        return Stream.of(
                "12345678",                 // invalid, only digit
                "abcdefgh",                 // invalid, only lowercase
                "ABCDEFGH",                 // invalid, only uppercase
                "abc123$$$",                // invalid, at least one uppercase
                "ABC123$$$",                // invalid, at least one lowercase
                "ABC$$$$$$",                // invalid, at least one digit
                "java REGEX 123",           // invalid, at least one special character
                "java REGEX 123 %",         // invalid, % is not in the special character group []
                "________",                 // invalid
                "--------",                 // invalid
                " ",                        // empty
                "");                        // empty
    }
} 

都通过了。

unit tests passed

4.常见问题

以下是一些常见问题:

  • 为什么密码越长越安全?
  • 为什么必须混合至少一个特殊字符?

回答 :
对于拉丁字符,小写和大写【a-zA-Z】,由 52 个字符组成;对于数字[0-9],由 10 个字符组成,共 62 个字符。

  • 如果密码长度为 1,则由62种可能性、【a-zA-Z0-9】组成。意思是最坏的情况;我们需要猜 62 次才能找到正确的密码。
  • 长度为 2 时,为62 x 6262 ^ 2 = 3,844
  • 62 ^ 3 = 238,328
  • 62 ^ 4 = 14,776,336
  • 62 ^ 5 = 916,132,832
  • 62 ^ 6 = 56,800,235,584
  • 62 ^ 7 = 3,521,614,606,208
  • 62 ^ 8 = 218,340,105,584,896
  • 较长的密码更安全,因为它使攻击者更难猜出正确的密码。明白了吗?

如果我们将标点符号! @ # & ( ) – [ { } ] : ; ' , ? / * (18 个字符)和符号~ $ ^ + = < > (7 个字符)等特殊字符包括在内,将会大大增加猜测正确密码的难度。我不是很确定有多少个特殊字符,姑且认为是 25 个字符(估计)。

对于 62 个字母数字字符+ 25 个特殊字符,总共是 87 个字符。

  • 87 ^ 1 = 87
  • 87 ^ 2 = 7,569
  • 87 ^ 3 = 658,503
  • 87 ^ 4 = 57,289,761
  • 87 ^ 5 = 4,984,209,207
  • 87 ^ 6 = 433,626,201,009
  • 87 ^ 7 = 37,725,479,487,783
  • 87 ^ 8 = 3,282,116,715,437,121

混有特殊字符会大大增加猜测正确密码的难度。

密码哈希
不将密码存储为明文。使用像 Argon2 这样的慢速散列来散列密码是一个很好的做法。

强密码生成器
试试这个 Java 密码生成器例子生成一个安全健壮的密码。

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-regex/password

参考

如何用正则表达式验证 12 小时格式的时间

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/regular-expressions/how-to-validate-time-in-12-hours-format-with-regular-expression/

12 小时格式正则表达式模式中的时间

 (1[012]|[1-9]):[0-5][0-9](\\s)?(?i)(am|pm) 

描述

 (				#start of group #1
 1[012]				#  start with 10, 11, 12
 |				#  or
 [1-9]				#  start with 1,2,...9
)				#end of group #1
 :				#    follow by a semi colon (:)
  [0-5][0-9]			#      follw by 0..5 and 0..9, which means 00 to 59
            (\\s)?		#        follow by a white space (optional)
                  (?i)		#          next checking is case insensitive
                      (am|pm)	#            follow by am or pm 

12 小时制格式是从 0-12 开始,然后是分号(😃,接着是 00-59,最后以 am 或 pm 结束。

Java 正则表达式示例

 package com.mkyong.regex;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Time12HoursValidator{

	  private Pattern pattern;
	  private Matcher matcher;

	  private static final String TIME12HOURS_PATTERN = 
                                "(1[012]|[1-9]):[0-5][0-9](\\s)?(?i)(am|pm)";

	  public Time12HoursValidator(){
		  pattern = Pattern.compile(TIME12HOURS_PATTERN);
	  }

	  /**
	   * Validate time in 12 hours format with regular expression
	   * @param time time address for validation
	   * @return true valid time fromat, false invalid time format
	   */
	  public boolean validate(final String time){		  
		  matcher = pattern.matcher(time);
		  return matcher.matches();	    	    
	  }
} 

匹配的时间格式:

1.“凌晨 1 点”,“凌晨 1 点”,“凌晨 1 点”,
2。“下午 1 点”,“下午 1 点”,“下午 1 点”,
3。"下午 12 点 50 分"

时间格式不匹配:

1.“0:00am”-小时超出范围[1-12]
2。“上午 10:00”——只允许一个空格
3。“1:00”——必须以 am 或 pm 结束
4。“23:00am”-不允许 24 小时格式
5。“1:61pm”-分钟超出范围[0-59]
6。“13:00pm”-小时超出范围[1-12]
7。“001:50pm”——无效的小时格式
8。“上午 10:99”-分钟超出范围[0-59]
9。“01:00pm”——不允许 24 小时格式
10。“1:00 BM”-必须以 am 或 pm 结束

单元测试–时间 12 小时验证测试

 package com.mkyong.regex;

import org.testng.Assert;
import org.testng.annotations.*;

/**
 * Time 12 hours format validator Testing
 * @author mkyong
 *
 */
public class Time12HoursValidatorTest {

	private Time12HoursValidator time12HoursValidator;

	@BeforeClass
        public void initData(){
		time12HoursValidator = new Time12HoursValidator();
        }

	@DataProvider
	public Object[][] ValidTime12HoursProvider() {
		return new Object[][]{
		     new Object[] {"1:00am"}, new Object[] {"1:00 am"}, 
                     new Object[] {"1:00 AM"}, new Object[] {"1:00pm"}, 
                     new Object[] {"1:00 pm"},new Object[] {"1:00 PM"},
		     new Object[] {"12:50 pm"}
		};
	}

	@DataProvider
	public Object[][] InvalidTime12HoursProvider() {
		return new Object[][]{
			 new Object[] {"0:00 am"},new Object[] {"10:00  am"},
			 new Object[] {"1:00"},new Object[] {"23:00 am"},
			 new Object[] {"1:61 pm"},new Object[] {"13:00 pm"},
			 new Object[] {"001:50 pm"},new Object[] {"10:99 am"},
			 new Object[] {"01:00 pm"}, new Object[] {"1:00 bm"}
		};
	}

	@Test(dataProvider = "ValidTime12HoursProvider")
	public void ValidTime12HoursTest(String time) {
	   boolean valid = time12HoursValidator.validate(time);
	   System.out.println("Time12Hours is valid : " + time + " , " + valid);
	   Assert.assertEquals(true, valid);
	}

	@Test(dataProvider = "InvalidTime12HoursProvider", 
                 dependsOnMethods="ValidTime12HoursTest")
	public void InValidTime12HoursTest(String time) {
	   boolean valid = time12HoursValidator.validate(time);
	   System.out.println("Time12Hours is valid : " + time + " , " + valid);
	   Assert.assertEquals(false, valid); 
	}	
} 

单元测试–结果

 Time12Hours is valid : 1:00am , true
Time12Hours is valid : 1:00 am , true
Time12Hours is valid : 1:00 AM , true
Time12Hours is valid : 1:00pm , true
Time12Hours is valid : 1:00 pm , true
Time12Hours is valid : 1:00 PM , true
Time12Hours is valid : 12:50 pm , true
Time12Hours is valid : 0:00 am , false
Time12Hours is valid : 10:00  am , false
Time12Hours is valid : 1:00 , false
Time12Hours is valid : 23:00 am , false
Time12Hours is valid : 1:61 pm , false
Time12Hours is valid : 13:00 pm , false
Time12Hours is valid : 001:50 pm , false
Time12Hours is valid : 10:99 am , false
Time12Hours is valid : 01:00 pm , false
Time12Hours is valid : 1:00 bm , false
PASSED: ValidTime12HoursTest("1:00am")
PASSED: ValidTime12HoursTest("1:00 am")
PASSED: ValidTime12HoursTest("1:00 AM")
PASSED: ValidTime12HoursTest("1:00pm")
PASSED: ValidTime12HoursTest("1:00 pm")
PASSED: ValidTime12HoursTest("1:00 PM")
PASSED: ValidTime12HoursTest("12:50 pm")
PASSED: InValidTime12HoursTest("0:00 am")
PASSED: InValidTime12HoursTest("10:00  am")
PASSED: InValidTime12HoursTest("1:00")
PASSED: InValidTime12HoursTest("23:00 am")
PASSED: InValidTime12HoursTest("1:61 pm")
PASSED: InValidTime12HoursTest("13:00 pm")
PASSED: InValidTime12HoursTest("001:50 pm")
PASSED: InValidTime12HoursTest("10:99 am")
PASSED: InValidTime12HoursTest("01:00 pm")
PASSED: InValidTime12HoursTest("1:00 bm")

===============================================
    com.mkyong.regex.Time12HoursValidatorTest
    Tests run: 17, Failures: 0, Skips: 0
===============================================

===============================================
mkyong
Total tests run: 17, Failures: 0, Skips: 0
=============================================== 

参考

http://en.wikipedia.org/wiki/12-hour_clock

想了解更多关于正则表达式的知识吗?强烈推荐这本最好最经典的书——《掌握正则表达式》

http://web.archive.org/web/20190214230831if_/http://rcm.amazon.com/e/cm?t=progrlife-20&o=1&p=8&l=as1&asins=0596528124&fc1=000000&IS2=1&lt1=_blank&m=amazon&lc1=0000FF&bc1=000000&bg1=FFFFFF&f=ifr

regex timestamp

如何用正则表达式验证 24 小时格式的时间

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/regular-expressions/how-to-validate-time-in-24-hours-format-with-regular-expression/

24 小时格式正则表达式模式中的时间

 ([01]?[0-9]|2[0-3]):[0-5][0-9] 

描述

 (				#start of group #1
 [01]?[0-9]			#  start with 0-9,1-9,00-09,10-19
 |				#  or
 2[0-3]				#  start with 20-23
)				#end of group #1
 :				#    follow by a semi colon (:)
  [0-5][0-9]			#      follw by 0..5 and 0..9, which means 00 to 59 

24 小时制格式是从 0-23 或 00-23 开始,然后是分号(😃,接着是 00-59。

Java 正则表达式示例

 package com.mkyong.regex;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Time24HoursValidator{

	  private Pattern pattern;
	  private Matcher matcher;

	  private static final String TIME24HOURS_PATTERN = 
                 "([01]?[0-9]|2[0-3]):[0-5][0-9]";

	  public Time24HoursValidator(){
		  pattern = Pattern.compile(TIME24HOURS_PATTERN);
	  }

	  /**
	   * Validate time in 24 hours format with regular expression
	   * @param time time address for validation
	   * @return true valid time fromat, false invalid time format
	   */
	  public boolean validate(final String time){

		  matcher = pattern.matcher(time);
		  return matcher.matches();

	  }
} 

匹配的时间格式:

1.“01:00”,“02:00”,“13:00”,
2。“1:00”,“2:00”,“13:01”,
3。" 23:59 " 15:00 "
4 . "00:00″,"0:00"

时间格式不匹配:

1.“24:00”-小时超出范围[0-23]
2。“12:60”——分钟超出范围[00-59]
3。“0:0”——分钟格式无效,至少两位数
4。“13:1”——无效的分钟格式,至少两位数
5。“101:00”-小时超出范围[0-23]

单元测试–时间 24 小时验证测试

 package com.mkyong.regex;

import org.testng.Assert;
import org.testng.annotations.*;

/**
 * Time 24 hours format validator Testing
 * @author mkyong
 *
 */
public class Time24HoursValidatorTest {

	private Time24HoursValidator time24HoursValidator;

	@BeforeClass
        public void initData(){
		time24HoursValidator = new Time24HoursValidator();
        }

	@DataProvider
	public Object[][] ValidTime24HoursProvider() {
		return new Object[][]{
			new Object[] {"01:00"}, new Object[] {"02:00"},
                        new Object[] {"13:00"}, new Object[] {"1:00"}, 
                        new Object[] {"2:00"},new Object[] {"13:01"},
		        new Object[] {"23:59"}, new Object[] {"15:00"},
		        new Object[] {"00:00"}, new Object[] {"0:00"}
		};
	}	

	@DataProvider
	public Object[][] InvalidTime24HoursProvider() {
		return new Object[][]{
			new Object[] {"24:00"},new Object[] {"12:60"},
			new Object[] {"0:0"},new Object[] {"13:1"},
			new Object[] {"101:00"}
		};
	}

	@Test(dataProvider = "ValidTime24HoursProvider")
	public void ValidTime24HoursTest(String time) {
	    boolean valid = time24HoursValidator.validate(time);
	    System.out.println("Time24Hours is valid : " + time + " , " + valid);
	    Assert.assertEquals(true, valid);
	}

	@Test(dataProvider = "InvalidTime24HoursProvider", 
                 dependsOnMethods="ValidTime24HoursTest")
	public void InValidTime24HoursTest(String time) {
	    boolean valid = time24HoursValidator.validate(time);
	    System.out.println("Time24Hours is valid : " + time + " , " + valid);
	    Assert.assertEquals(false, valid); 
	}	
} 

单元测试–结果

 Time24Hours is valid : 01:00 , true
Time24Hours is valid : 02:00 , true
Time24Hours is valid : 13:00 , true
Time24Hours is valid : 1:00 , true
Time24Hours is valid : 2:00 , true
Time24Hours is valid : 13:01 , true
Time24Hours is valid : 23:59 , true
Time24Hours is valid : 15:00 , true
Time24Hours is valid : 00:00 , true
Time24Hours is valid : 0:00 , true
Time24Hours is valid : 24:00 , false
Time24Hours is valid : 12:60 , false
Time24Hours is valid : 0:0 , false
Time24Hours is valid : 13:1 , false
Time24Hours is valid : 101:00 , false
PASSED: ValidTime24HoursTest("01:00")
PASSED: ValidTime24HoursTest("02:00")
PASSED: ValidTime24HoursTest("13:00")
PASSED: ValidTime24HoursTest("1:00")
PASSED: ValidTime24HoursTest("2:00")
PASSED: ValidTime24HoursTest("13:01")
PASSED: ValidTime24HoursTest("23:59")
PASSED: ValidTime24HoursTest("15:00")
PASSED: ValidTime24HoursTest("00:00")
PASSED: ValidTime24HoursTest("0:00")
PASSED: InValidTime24HoursTest("24:00")
PASSED: InValidTime24HoursTest("12:60")
PASSED: InValidTime24HoursTest("0:0")
PASSED: InValidTime24HoursTest("13:1")
PASSED: InValidTime24HoursTest("101:00")

===============================================
    com.mkyong.regex.Time24HoursValidatorTest
    Tests run: 15, Failures: 0, Skips: 0
===============================================

===============================================
mkyong
Total tests run: 15, Failures: 0, Skips: 0
=============================================== 

参考

http://en.wikipedia.org/wiki/24-hour_clock

想了解更多关于正则表达式的知识吗?强烈推荐这本经典的书——《掌握正则表达式》

http://web.archive.org/web/20190311020049if_/http://rcm.amazon.com/e/cm?t=progrlife-20&o=1&p=8&l=as1&asins=0596528124&fc1=000000&IS2=1&lt1=_blank&m=amazon&lc1=0000FF&bc1=000000&bg1=FFFFFF&f=ifr

regex timestamp

Java regex 验证用户名示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/regular-expressions/how-to-validate-username-with-regular-expression/

Java regex username

本文展示了如何使用 regex 在 Java 中验证用户名。

用户名要求

  1. 用户名由字母数字字符(a-zA-Z0-9)、小写字母或大写字母组成。
  2. 点()允许的用户名。)、下划线(_)和连字符(-)。
  3. 圆点(。)、下划线(_)或连字符(-)不能是第一个或最后一个字符。
  4. 圆点(。)、下划线(_)或连字符(-)不会连续出现,例如 java..正则表达式
  5. 字符数必须在 5 到 20 之间。

下面是符合上述所有要求的正则表达式。

 ^[a-zA-Z0-9]([._-](?![._-])|[a-zA-Z0-9]){3,18}[a-zA-Z0-9]$ 

1.用户名正则表达式解释

下面是用户名正则表达式的解释。

 ^[a-zA-Z0-9]      # start with an alphanumeric character
  (                 # start of (group 1)
    [._-](?![._-])  # follow by a dot, hyphen, or underscore, negative lookahead to
                    # ensures dot, hyphen, and underscore does not appear consecutively
    |               # or
    [a-zA-Z0-9]     # an alphanumeric character
  )                 # end of (group 1)
  {3,18}            # ensures the length of (group 1) between 3 and 18
  [a-zA-Z0-9]$      # end with an alphanumeric character

                    # {3,18} plus the first and last alphanumeric characters,
                    # total length became {5,20} 

是什么?!
正则符号?!是一个负前瞻,确保某个东西后面没有其他东西;例如,_(?!_)确保下划线后面没有下划线。

2.验证用户名的正则表达式

下面是一个使用上述正则表达式验证用户名的 Java 示例。

UsernameValidator.java

 package com.mkyong.regex.username;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class UsernameValidator {

    // simple regex
    //private static final String USERNAME_PATTERN = "^[a-z0-9\\._-]{5,20}$";

    // strict regex
    private static final String USERNAME_PATTERN =
            "^[a-zA-Z0-9]([._-](?![._-])|[a-zA-Z0-9]){3,18}[a-zA-Z0-9]$";

    private static final Pattern pattern = Pattern.compile(USERNAME_PATTERN);

    public static boolean isValid(final String username) {
        Matcher matcher = pattern.matcher(username);
        return matcher.matches();
    }

} 

3.用户名正则表达式单元测试

下面是验证有效和无效用户名列表的单元测试。

UsernameValidatorTest.java

 package com.mkyong.regex.username;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class UsernameValidatorTest {

    @ParameterizedTest(name = "#{index} - Run test with username = {0}")
    @MethodSource("validUsernameProvider")
    void test_username_regex_valid(String username) {
        assertTrue(UsernameValidator.isValid(username));
    }

    @ParameterizedTest(name = "#{index} - Run test with username = {0}")
    @MethodSource("invalidUsernameProvider")
    void test_username_regex_invalid(String username) {
        assertFalse(UsernameValidator.isValid(username));
    }

    static Stream<String> validUsernameProvider() {
        return Stream.of(
                "mkyong",
                "javaregex",
                "JAVAregex",
                "java.regex",
                "java-regex",
                "java_regex",
                "java.regex.123",
                "java-regex-123",
                "java_regex_123",
                "javaregex123",
                "123456",
                "java123",
                "01234567890123456789");
    }

    static Stream<String> invalidUsernameProvider() {
        return Stream.of(
                "abc",                      // invalid length 3, length must between 5-20
                "01234567890123456789a",    // invalid length 21, length must between 5-20
                "_javaregex_",              // invalid start and last character
                ".javaregex.",              // invalid start and last character
                "-javaregex-",              // invalid start and last character
                "javaregex#$%@123",         // invalid symbols, support dot, hyphen and underscore
                "java..regex",              // dot cant appear consecutively
                "java--regex",              // hyphen can't appear consecutively
                "java__regex",              // underscore can't appear consecutively
                "java._regex",              // dot and underscore can't appear consecutively
                "java.-regex",              // dot and hyphen can't appear consecutively
                " ",                        // empty
                "");                        // empty
    }

} 

都通过了。

unit tests passedunit tests passed

4.反正则表达式,Java 用户名验证器

下面是反正则表达式开发人员验证用户名的等效 Java 代码(满足上述用户名的所有要求)。

UsernameValidatorCode.java

 package com.mkyong.regex.username;

public class UsernameValidatorCode {

    private static final char[] SUPPORT_SYMBOLS_CHAR = {'.', '_', '-'};

    public static boolean isValid(final String username) {

        // check empty
        if (username == null || username.length() == 0) {
            return false;
        }

        // check length
        if (username.length() < 5 || username.length() > 20) {
            return false;
        }

        return isValidUsername(username.toCharArray());
    }

    private static boolean isValidUsername(final char[] username) {

        int currentPosition = 0;
        boolean valid = true;

        // check char by char
        for (char c : username) {

            // if alphanumeric char, no need check, process next
            if (!Character.isLetterOrDigit(c)) {

                // for non-alphanumeric char, also not a supported symbol, break
                if (!isSupportedSymbols(c)) {
                    valid = false;
                    break;
                }

                // ensures first and last char not a supported symbol
                if (username[0] == c || username[username.length - 1] == c) {
                    valid = false;
                    break;
                }

                // ensure supported symbol does not appear consecutively
                // is next position also a supported symbol?
                if (isSupportedSymbols(username[currentPosition + 1])) {
                    valid = false;
                    break;
                }

            }

            currentPosition++;
        }

        return valid;

    }

    private static boolean isSupportedSymbols(final char symbol) {
        for (char temp : SUPPORT_SYMBOLS_CHAR) {
            if (temp == symbol) {
                return true;
            }
        }
        return false;
    }

} 

同样的#3 单元再次测试,用上面的 Java 用户名验证器替换 regex 验证器,所有测试都通过了。

延伸阅读
如果你使用 email 作为用户名,试试这个 Java email regex 例子

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ CD Java-regex/用户名

参考

如何在 Java 中读写图像

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-write-an-image-to-file-imageio/

在 Java 中,我们可以使用 javax.imageio.ImageIO 类来读写图像。

1.阅读图像

从文件中读取图像。

 BufferedImage image = ImageIO.read(new File("c:\\test\\image.png")); 

从 URL 读取图像。

 BufferedImage image = ImageIO.read(new URL("https://example.com/image.png")); 

2.编写或保存图像

以不同的图像格式编写或保存图像。

 ImageIO.write(bufferedImage , "jpg", new File("c:\\test\\image.jpg"));

  ImageIO.write(bufferedImage , "gif", new File("c:\\test\\image.gif"));

  ImageIO.write(bufferedImage , "png", new File("c:\\test\\image.png")); 

下面的代码片段列出了所有支持的格式。

 String writerNames[] = ImageIO.getWriterFormatNames();
  Arrays.stream(writerNames).forEach(System.out::println); 

输出

 PG
jpg
tiff
bmp
BMP
gif
GIF
WBMP
png
PNG
JPEG
tif
TIF
TIFF
wbmp
jpeg 

3.读取、调整和保存图像。

一个完整的 Java 例子,使用ImageIO从一个 URL (Google logo)中读取一个图像,将其大小调整为300x150并保存到一个文件中。

ReadWriteImage.java

 package com.mkyong.io.image;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

public class ReadWriteImage {

    // Google logo url
    private static final String GOOGLE_LOGO =
            "https://www.google.cimg/branding/googlelogo/2x/googlelogo_color_272x92dp.png";

    public static void main(String[] args) {

        try {

            URL url = new URL(GOOGLE_LOGO);

            // read an image from url
            BufferedImage image = ImageIO.read(url);

            // resize image to 300x150
            Image scaledImage = image.getScaledInstance(300, 150, Image.SCALE_DEFAULT);

            // save the resize image aka thumbnail
            ImageIO.write(
                    convertToBufferedImage(scaledImage),
                    "png",
                    new File("C:\\test\\google.png"));

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("Done");

    }

    // convert Image to BufferedImage
    public static BufferedImage convertToBufferedImage(Image img) {

        if (img instanceof BufferedImage) {
            return (BufferedImage) img;
        }

        // Create a buffered image with transparency
        BufferedImage bi = new BufferedImage(
                img.getWidth(null), img.getHeight(null),
                BufferedImage.TYPE_INT_ARGB);

        Graphics2D graphics2D = bi.createGraphics();
        graphics2D.drawImage(img, 0, 0, null);
        graphics2D.dispose();

        return bi;
    }

} 

下载的图像大小调整为 300×150。

read-resize-write-image

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-io/howto/images

参考

如何用 Java 编写 UTF 8 文件

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-write-utf-8-encoded-data-into-a-file-java/

在 Java 中, OutputStreamWriter 接受一个字符集来将字符流编码成字节流。我们可以将一个StandardCharsets.UTF_8传递给OutputStreamWriter构造函数,将数据写入一个 UTF-8 文件。

 try (FileOutputStream fos = new FileOutputStream(file);
       OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
       BufferedWriter writer = new BufferedWriter(osw)) {

      writer.append(line);

  } 

在 Java 7+中,许多文件 I/O 和 NIO 编写器开始接受charset作为参数,这使得将数据写入 UTF-8 文件变得非常容易,例如:

 // Java 7
  Files.write(path, lines, StandardCharsets.UTF_8);

  // Java 8
  Files.newBufferedWriter(path) // default UTF-8

  // Java 11
  new FileWriter(new File(fileName), StandardCharsets.UTF_8); 

1.写入 UTF-8 文件

这个例子展示了一些将中文字符写入 UTF 8 文件的方法。

UnicodeWrite.java

 package com.mkyong.io.howto;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;

public class UnicodeWrite {

    public static void main(String[] args) {

        String fileName = "c:\\temp\\test.txt";
        List<String> lines = Arrays.asList("line 1", "line 2", "line 3", "你好,世界");

        writeUnicodeJava7(fileName, lines);
        //writeUnicodeJava8(fileName, lines);
        //writeUnicodeJava11(fileName, lines);
        //writeUnicodeClassic(fileName, lines);

        System.out.println("Done");
    }

    // in the old days
    public static void writeUnicodeClassic(String fileName, List<String> lines) {

        File file = new File(fileName);

        try (FileOutputStream fos = new FileOutputStream(file);
             OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
             BufferedWriter writer = new BufferedWriter(osw)
        ) {

            for (String line : lines) {
                writer.append(line);
                writer.newLine();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void writeUnicodeJava7(String fileName, List<String> lines) {

        Path path = Paths.get(fileName);
        try {
            Files.write(path, lines, StandardCharsets.UTF_8);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    // Java 8 - Files.newBufferedWriter(path) - default UTF-8
    public static void writeUnicodeJava8(String fileName, List<String> lines) {

        Path path = Paths.get(fileName);

        try (BufferedWriter writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) {

            for (String line : lines) {
                writer.append(line);
                writer.newLine();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    // Java 11 adds Charset to FileWriter
    public static void writeUnicodeJava11(String fileName, List<String> lines) {

        try (FileWriter fw = new FileWriter(new File(fileName), StandardCharsets.UTF_8);
             BufferedWriter writer = new BufferedWriter(fw)) {

            for (String line : lines) {
                writer.append(line);
                writer.newLine();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

} 

输出

utf-8 file

延伸阅读
如何在 Java 中读取一个 UTF-8 文件

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-io

参考

如何用 Java 编写 XML 文件(StAX Writer)

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-write-xml-file-in-java-stax-writer/

本教程展示了如何使用Streaming API for XML(StAX)writer 将数据写入 XML 文件。

目录

注意
如何在 Java 中读取 XML 文件(StAX Parser)

下面所有的例子都是用 Java 11 测试的。

1。写入 XML (StAX 编写器 API)

在 Streaming API for XML (StAX)中,我们可以使用StAX Cursor APIStAX Iterator API将数据写入 XML 文件。

1.1 下面是将数据写入 XML 的StAX Cursor API

 XMLOutputFactory output = XMLOutputFactory.newInstance();

  XMLStreamWriter writer = output.createXMLStreamWriter(
                              new FileOutputStream("/path/test.xml"));

  writer.writeStartDocument();

  writer.writeStartElement("test");

  // write other XML elements

  writer.writeEndDocument();

  writer.flush();

  writer.close(); 

1.2 下面是将数据写入 XML 的StAX Iterator API

 XMLOutputFactory output = XMLOutputFactory.newInstance();

  XMLEventFactory eventFactory = XMLEventFactory.newInstance();

  XMLEventWriter writer = output.createXMLEventWriter(
                            new FileOutputStream("/path/test.xml"));

  XMLEvent event = eventFactory.createStartDocument();
  writer.add(event);

  // add other xml events

  writer.add(eventFactory.createEndDocument());

  writer.flush();

  writer.close(); 

2。写入 XML(StAX Cursor API–XML streamwriter)

以下示例使用 StAX Cursor API XMLStreamWriter将数据写入 XML 文件。

WriteXmlStAXCursor.java

 package com.mkyong.xml.stax;

import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class WriteXmlStAXCursor {

    public static void main(String[] args) throws XMLStreamException {

        // send the output to a xml file
        try(FileOutputStream out = new FileOutputStream("/home/mkyong/test.xml")){
            writeXml(out);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // send the output to System.out
        // writeXml(System.out);

    }

    // StAX Cursor API
    private static void writeXml(OutputStream out) throws XMLStreamException {

        XMLOutputFactory output = XMLOutputFactory.newInstance();

        XMLStreamWriter writer = output.createXMLStreamWriter(out);

        writer.writeStartDocument("utf-8", "1.0");

        // <company>
        writer.writeStartElement("company");

        // <staff>

        // add XML comment
        writer.writeComment("This is Staff 1001");

        writer.writeStartElement("staff");
        writer.writeAttribute("id", "1001");

        writer.writeStartElement("name");
        writer.writeCharacters("mkyong");
        writer.writeEndElement();

        writer.writeStartElement("salary");
        writer.writeAttribute("currency", "USD");
        writer.writeCharacters("5000");
        writer.writeEndElement();

        writer.writeStartElement("bio");
        writer.writeCData("HTML tag <code>testing</code>");
        writer.writeEndElement();

        writer.writeEndElement();
        // </staff>

        // <staff>
        writer.writeStartElement("staff");
        writer.writeAttribute("id", "1002");

        writer.writeStartElement("name");
        writer.writeCharacters("yflow");
        writer.writeEndElement();

        writer.writeStartElement("salary");
        writer.writeAttribute("currency", "EUR");
        writer.writeCharacters("8000");
        writer.writeEndElement();

        writer.writeStartElement("bio");
        writer.writeCData("a & b");
        writer.writeEndElement();

        writer.writeEndElement();
        // </staff>

        writer.writeEndDocument();
        // </company>

        writer.flush();

        writer.close();

    }

} 

XMLStreamWriter以压缩模式将数据写入 XML 文件,稍后我们将使用Transformer打印 XML 内容。

/home/mkyong/test.xml

 <?xml version="1.0" encoding="utf-8"?><company>
<!--This is Staff 1001--><staff id="1001"><name>mkyong</name><salary currency="USD">5000</salary>
<bio><![CDATA[HTML tag <code>testing</code>]]></bio></staff>
<staff id="1002"><name>yflow</name><salary currency="EUR">8000</salary>
<bio><![CDATA[a & b]]></bio></staff></company> 

3。写入 XML (StAX 迭代器 API–XMLEventWriter)

下面的例子使用 StAX 迭代器 API XMLEventWriter将数据写入 XML 文件。

WriteXmlStAXIterator.java

 package com.mkyong.xml.stax;

import javax.xml.stream.*;
import javax.xml.stream.events.XMLEvent;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class WriteXmlStAXIterator {

    public static void main(String[] args) throws XMLStreamException {

        // send the output to a xml file
        try(FileOutputStream out = new FileOutputStream("/home/mkyong/test.xml")){
            writeXml2(out);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // send the output to System.out
        // writeXml2(System.out);

    }

    // StAX Iterator API
    private static void writeXml2(OutputStream out) throws XMLStreamException {

        XMLOutputFactory output = XMLOutputFactory.newInstance();
        XMLEventFactory eventFactory = XMLEventFactory.newInstance();

        // StAX Iterator API
        XMLEventWriter writer = output.createXMLEventWriter(out);

        XMLEvent event = eventFactory.createStartDocument();
        // default
        //event = eventFactory.createStartDocument("utf-8", "1.0");
        writer.add(event);

        writer.add(eventFactory.createStartElement("", "", "company"));

        // write XML comment
        writer.add(eventFactory.createComment("This is staff 1001"));

        writer.add(eventFactory.createStartElement("", "", "staff"));
        // write XML attribute
        writer.add(eventFactory.createAttribute("id", "1001"));

        writer.add(eventFactory.createStartElement("", "", "name"));
        writer.add(eventFactory.createCharacters("mkyong"));
        writer.add(eventFactory.createEndElement("", "", "name"));

        writer.add(eventFactory.createStartElement("", "", "salary"));
        writer.add(eventFactory.createAttribute("currency", "USD"));
        writer.add(eventFactory.createCharacters("5000"));
        writer.add(eventFactory.createEndElement("", "", "salary"));

        writer.add(eventFactory.createStartElement("", "", "bio"));
        // write XML CData
        writer.add(eventFactory.createCData("HTML tag <code>testing</code>"));
        writer.add(eventFactory.createEndElement("", "", "bio"));

        // </staff>
        writer.add(eventFactory.createEndElement("", "", "staff"));

        // next staff, tired to write more
        // writer.add(eventFactory.createStartElement("", "", "staff"));
        // writer.add(eventFactory.createAttribute("id", "1002"));
        // writer.add(eventFactory.createEndElement("", "", "staff"));

        // end here.
        writer.add(eventFactory.createEndDocument());

        writer.flush();

        writer.close();

    }

} 

输出

/home/mkyong/test.xml

 <?xml version="1.0" encoding="UTF-8"?><company>
<!--This is staff 1001--><staff id="1001"><name>mkyong</name>
<salary currency="USD">5000</salary>
<bio><![CDATA[HTML tag <code>testing</code>]]></bio>
</staff></company> 

4。编写并漂亮打印 XML 内容(Transformer)

4.1 下面的代码片段使用javax.xml.transform.Transformer来打印一个 XML 内容。

 private static String formatXML(String xml) throws TransformerException {

      // write data to xml file
      TransformerFactory transformerFactory = TransformerFactory.newInstance();

      Transformer transformer = transformerFactory.newTransformer();

      // alternative
      //Transformer transformer = SAXTransformerFactory.newInstance().newTransformer();

      // pretty print by indention
      transformer.setOutputProperty(OutputKeys.INDENT, "yes");

      // add standalone="yes", add line break before the root element
      transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");

      /*transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,
              "-//W3C//DTD XHTML 1.0 Transitional//EN");

      transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
              "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd");*/

      // ignore <?xml version="1.0" encoding="UTF-8"?>
      //transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");

      StreamSource source = new StreamSource(new StringReader(xml));
      StringWriter output = new StringWriter();
      transformer.transform(source, new StreamResult(output));

      return output.toString();

  } 

4.2 美化 XML 内容的步骤。

  1. 将数据写入ByteArrayOutputStream变量。
  2. ByteArrayOutputStream变量转换成字符串。
  3. Transformer输出字符串并返回一个格式化的 XML 字符串。
  4. 将格式化的 XML 字符串保存到文件中。

下面的例子打印 XML 内容并写入一个 XML 文件。

WriteXmlStAXPrettyPrint.java

 package com.mkyong.xml.stax;

import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

public class WriteXmlStAXPrettyPrint {

    public static void main(String[] args) {

        try {

            ByteArrayOutputStream out = new ByteArrayOutputStream();
            // write XML to ByteArrayOutputStream
            writeXml(out);

            // Java 10
            //String xml = out.toString(StandardCharsets.UTF_8);

            // standard way to convert byte array to String
            String xml = new String(out.toByteArray(), StandardCharsets.UTF_8);

            // System.out.println(formatXML(xml));

            String prettyPrintXML = formatXML(xml);

            // print to console
            // System.out.println(prettyPrintXML);

            // Java 11 - write to file
            Files.writeString(Paths.get("/home/mkyong/test.xml"),
                    prettyPrintXML, StandardCharsets.UTF_8);

            // Java 7 - write to file
            //Files.write(Paths.get("/home/mkyong/test.xml"),
            //    prettyPrintXML.getBytes(StandardCharsets.UTF_8));

            // BufferedWriter - write to file
            /*try (FileWriter writer = new FileWriter("/home/mkyong/test.xml");
                 BufferedWriter bw = new BufferedWriter(writer)) {
                bw.write(xml);
            } catch (IOException e) {
                e.printStackTrace();
            }*/

        } catch (TransformerException | XMLStreamException | IOException e) {
            e.printStackTrace();
        }

    }

    // StAX Cursor API
    private static void writeXml(OutputStream out) throws XMLStreamException {

        XMLOutputFactory output = XMLOutputFactory.newInstance();

        XMLStreamWriter writer = output.createXMLStreamWriter(out);

        writer.writeStartDocument("utf-8", "1.0");

        // <company>
        writer.writeStartElement("company");

        // <staff>
        // add XML comment
        writer.writeComment("This is Staff 1001");

        writer.writeStartElement("staff");
        writer.writeAttribute("id", "1001");

        writer.writeStartElement("name");
        writer.writeCharacters("mkyong");
        writer.writeEndElement();

        writer.writeStartElement("salary");
        writer.writeAttribute("currency", "USD");
        writer.writeCharacters("5000");
        writer.writeEndElement();

        writer.writeStartElement("bio");
        writer.writeCData("HTML tag <code>testing</code>");
        writer.writeEndElement();

        writer.writeEndElement();
        // </staff>

        // <staff>
        writer.writeStartElement("staff");
        writer.writeAttribute("id", "1002");

        writer.writeStartElement("name");
        writer.writeCharacters("yflow");
        writer.writeEndElement();

        writer.writeStartElement("salary");
        writer.writeAttribute("currency", "EUR");
        writer.writeCharacters("8000");
        writer.writeEndElement();

        writer.writeStartElement("bio");
        writer.writeCData("a & b");
        writer.writeEndElement();

        writer.writeEndElement();
        // </staff>

        writer.writeEndDocument();
        // </company>

        writer.flush();

        writer.close();

    }

    private static String formatXML(String xml) throws TransformerException {

        // write data to xml file
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();

        // pretty print by indention
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");

        // add standalone="yes", add line break before the root element
        transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");

        StreamSource source = new StreamSource(new StringReader(xml));
        StringWriter output = new StringWriter();
        transformer.transform(source, new StreamResult(output));

        return output.toString();

    }

} 

输出

/home/mkyong/test.xml

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<company>
    <!--This is Staff 1001-->
    <staff id="1001">
        <name>mkyong</name>
        <salary currency="USD">5000</salary>
        <bio>
            <![CDATA[HTML tag <code>testing</code>]]>
        </bio>
    </staff>
    <staff id="1002">
        <name>yflow</name>
        <salary currency="EUR">8000</salary>
        <bio>
            <![CDATA[a & b]]>
        </bio>
    </staff>
</company> 

将 XML 转换成 Java 对象
试试 Jakarta XML Binding (JAXB) 将 XML 转换成 Java 对象/从 Java 对象转换过来。

5。下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-xml

$ CD src/main/Java/com/mkyong/XML/StAX/

6。参考文献

JSF 2.0 中的隐式导航

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/implicit-navigation-in-jsf-2-0/

在 JSF 1.2 中,所有的页面导航都需要在"faces-config.xml"文件中声明如下:

 ...
<navigation-rule>
   <from-view-id>page1.xhtml</from-view-id>
   <navigation-case>
       <from-outcome>page2</from-outcome>
       <to-view-id>/page2.xhtml</to-view-id>
   </navigation-case>
</navigation-rule>
... 

在 JSF 2 中,它将“结果”作为页面名称,例如,导航到“page1.xhtml”,您必须将“结果”作为“page1”。这种机制被称为“隐式导航”,在这里你不需要声明繁琐的导航规则,而是直接把“结果”放在动作属性中,JSF 就会自动找到正确的“视图 id ”。

在 JSF 2 中有两种方法来实现隐式导航。

1.JSF 的结果页面

你可以把“结果”直接放在 JSF 页面上。

page 1 . XHTML–一个 JSF 页面,带有一个从当前页面移动到“page2.xhtml”的命令按钮。

 <h:form>
    <h:commandButton action="page2" value="Move to page2.xhtml" />
</h:form> 

点击按钮后,JSF 会将动作值或结果,“ page2 ”与“ xhtml ”扩展名合并,在当前的“ page1.xhtml 目录中找到视图名“ page2.xhtml ”。

2.受管 Bean 的结果

此外,您还可以像这样定义受管 bean 中的“结果”:

PageController.java

 @ManagedBean
@SessionScoped
public class PageController implements Serializable {

	public String moveToPage2(){
	    return "page2"; //outcome
	}
} 

在 JSF 页面中,action 属性,只需使用“方法表达式调用方法即可。

page1.xhtml

 <h:form>
    <h:commandButton action="#{pageController.moveToPage2}" 
	value="Move to page2.xhtml by managed bean" />
</h:form> 

重寄

默认情况下,JSF 2 是执行一个前进,而导航到另一个页面,这导致该页面的网址总是落后一个:)。例如,当您从“page1.xhtml”移动到“page2.xhtml”时,浏览器 URL 地址栏仍会显示相同的“page 1 . XHTML”URL。

为了避免这种情况,您可以通过在“outcome”字符串的末尾附加“ faces-redirect=true ”来告诉 JSF 使用重定向。

 <h:form>
    <h:commandButton action="page2?faces-redirect=true" value="Move to page2.xhtml" />
</h:form> 

Note
For simple page navigation, this new implicit navigation is more then enough; For complex page navigation, you are still allow to declare the page flow (navigation rule) in the faces-config.xml file.

下载源代码

Download it – JSF-2-Implicit-Navigation-Example.zip (10KB)Tags : jsf2 navigation rule

将 Spring XML 文件导入@Configuration

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring3/import-spring-xml-files-into-configuration/

将 XML 配置混合到 Spring @Configuration中是很常见的,因为开发人员已经习惯了 XML 名称空间。在 Spring 中,您可以使用@ImportResource将 Spring XML 配置文件导入到@Configuration中:

AppConfig.java

 import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

@Configuration
@ImportResource("classpath:/config/spring.xml")
public class AppConfig {

} 

另一个例子

AppConfig.java

 import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.Import;

@Configuration
@Import({ AppConfigWeb.class })
@ImportResource("classpath:/config/spring.xml")
public class AppConfig {

} 

P.S @ImportResource自春季 3.0 开始发售

spring spring config spring3 (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190309055132/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

不兼容 class 错误:JobDetailBean 将接口 org.quartz.JobDetail 作为超类

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring/incompatibleclasschangeerror-jobdetailbean-has-interface-org-quartz-jobdetail-as-super-class/

开发石英 2.1.5 + 弹簧 3.1.2 .释放,出现以下错误信息:

 Caused by: java.lang.IncompatibleClassChangeError: 
	class org.springframework.scheduling.quartz.JobDetailBean has interface org.quartz.JobDetail as super class
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
	at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2901)
	at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1170)
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1678)
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1556)
	at org.springframework.util.ClassUtils.forName(ClassUtils.java:258)
	... 19 more 

解决办法

Quartz 2 APIs 变化很大,已经有人在 Spring JIRA 上填了一个 bug 报告。这时,“弹簧 3 与石英 2 不兼容”。

这里有三种选择:

  1. 使用石英 1.8.5,弹簧 3 与石英 1.x 大集成,经典且稳定。
  2. 不使用 Spring 的QuartzJobBean进行集成,直接使用 Quartz 的接口/类。
  3. 最后,还有什么?请等待错误修复。

quartz spring (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190205235332/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

在 JSF 2.0 中注入受管 beans

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/injecting-managed-beans-in-jsf-2-0/

在 JSF 2.0 中,一个新的 @ManagedProperty 注释用于将一个受管 bean 依赖注入(DI)到另一个受管 bean 的属性中。

让我们看一个 @ManagedProperty 的例子:

MessageBean.java——名为“消息的托管 bean。

 import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean(name="message")
@SessionScoped
public class MessageBean implements Serializable {

	//business logic and whatever methods...

} 

——将消息bean 注入到“消息 Bean** 属性中。**

 `import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;

@ManagedBean
@SessionScoped
public class HelloBean implements Serializable {

	@ManagedProperty(value="#{message}")
	private MessageBean messageBean;

	//must povide the setter method
	public void setMessageBean(MessageBean messageBean) {
		this.messageBean = messageBean;
	}

	//...
}` 

在本例中,它使用了 @ManagedProperty 注释,通过 setter 方法 setMessageBean() ,将“消息”bean(【MessageBean.java】)解析为“你好”bean(【HelloBean.java】)的属性( messageBean )。

Note
To make this injection successful, the inject property (messageBean) must provide the setter method.

下载源代码

Download it – JSF-2-Inject-Managed-Beans-Example.zip (10KB)

参考

  1. ManagedProperty Javadoc
  2. JSF 2.0:受管 bean x 不存在,检查适当的 getter 和/或 setter 方法是否存在

**Tags : jsf2 managed bean****

相关文章

如何在 macOS 上安装 Maven

原文:http://web.archive.org/web/20230101150211/https://www.mkyong.com/maven/install-maven-on-mac-osx/

本文展示了如何在 macOS Big Sur(版本 11.1)上安装 Maven (3.6.3)。

主题

  1. 自制安装 Maven
  2. 手动安装 Maven

相关文章

1。自制在 macOS 上安装 Maven

1.1 安装 Homebrew ,macOS 上的一个包管理器。

1.2 命令brew install maven将安装最新的 Maven。

Terminal

 % brew install maven 

1.3 搞定。Maven 安装在 macOS 上。

Terminal

 % mvn -version

Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: /usr/local/Cellar/maven/3.6.3_1/libexec
Java version: 15.0.1, vendor: N/A, runtime: /usr/local/Cellar/openjdk/15.0.1/libexec/openjdk.jdk/Contents/Home
Default locale: en_MY, platform encoding: UTF-8
OS name: "mac os x", version: "10.16", arch: "x86_64", family: "mac" 

P.S 在撰写本文时,最新的 Maven 版本是 3.6.3

1.4 家酿在哪里安装了 Maven?
brew将在/usr/local/Cellar/maven/${version}安装 Maven 包

Terminal

 % ls -lsa /usr/local/Cellar/maven/3.6.3_1
total 72
0 drwxr-xr-x  9 mkyong  admin    288 Jan 11 11:10 .
0 drwxr-xr-x  3 mkyong  admin     96 Jan 11 11:10 ..
0 drwxr-xr-x  3 mkyong  admin     96 Jan 11 11:10 .brew
8 -rw-r--r--  1 mkyong  admin    756 Jan 11 11:10 INSTALL_RECEIPT.json
40 -rw-r--r--  1 mkyong  admin  17504 Nov  7  2019 LICENSE
16 -rw-r--r--  1 mkyong  admin   5141 Nov  7  2019 NOTICE
8 -rw-r--r--  1 mkyong  admin   2612 Nov  7  2019 README.txt
0 drwxr-xr-x  5 mkyong  admin    160 Jan 11 11:10 bin
0 drwxr-xr-x  6 mkyong  admin    192 Jan 11 11:10 libexec 

brew也在/usr/local/opt/maven/创建快捷方式或符号链接

Terminal

 % ls -lsa /usr/local/opt/ | grep maven

0 lrwxr-xr-x   1 mkyong  admin    23 Jan 11 11:10 maven -> ../Cellar/maven/3.6.3_1 

1.5 家酿把 Maven 配置文件settings.xml放在哪里?
settings.xml/usr/local/opt/maven/libexec/conf有售

Terminal

 # real path
/usr/local/Cellar/maven/3.6.3_1/libexec/conf

# symbolic links to the above path
/usr/local/opt/maven/libexec/conf 

Terminal

 % ls -lsa /usr/local/opt/maven/libexec/conf
total 32
 0 drwxr-xr-x  5 mkyong  admin    160 Jan 14 07:02 .
 0 drwxr-xr-x  6 mkyong  admin    192 Jan 11 11:10 ..
 0 drwxr-xr-x  3 mkyong  admin     96 Nov  7  2019 logging
24 -rw-r--r--  1 mkyong  admin  10468 Nov  7  2019 settings.xml
 8 -rw-r--r--  1 mkyong  admin   3747 Nov  7  2019 toolchains.xml 

1.6 家酿把核心mvn可执行文件放在哪里?
mvn/usr/local/bin/

Terminal

 % ls -lsah /usr/local/bin/mvn

0 lrwxr-xr-x  1 mkyong  admin    31B Jan 11 11:10 /usr/local/bin/mvn -> ../Cellar/maven/3.6.3_1/bin/mvn 

1.7 brew info maven显示 Maven 包的细节。

Terminal

 % brew info maven   

maven: stable 3.6.3
Java-based project management
https://maven.apache.org/
Conflicts with:
  mvnvm (because also installs a 'mvn' executable)
/usr/local/Cellar/maven/3.6.3_1 (87 files, 10.7MB) *
  Built from source on 2021-01-11 at 11:10:48
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/maven.rb
License: Apache-2.0
==> Dependencies
Required: openjdk ✔ 

1.8 brew list maven

Terminal

 % brew list maven
/usr/local/Cellar/maven/3.6.3_1/bin/mvn
/usr/local/Cellar/maven/3.6.3_1/bin/mvnDebug
/usr/local/Cellar/maven/3.6.3_1/bin/mvnyjp
/usr/local/Cellar/maven/3.6.3_1/libexec/bin/ (4 files)
/usr/local/Cellar/maven/3.6.3_1/libexec/boot/ (2 files)
/usr/local/Cellar/maven/3.6.3_1/libexec/conf/ (3 files)
/usr/local/Cellar/maven/3.6.3_1/libexec/lib/ (70 files) 

1.9 有用的命令:

  • brew upgrade maven升级 Maven。
  • brew uninstall maven卸载 Maven。

2。手动安装 Maven】

如果家酿失败了,或者你不想要黑盒魔术,尝试手动安装 Maven。

2.1 下载 Maven ,例如apache-maven-3.6.3-bin.tar.gz

Install Maven on macOS

2.2 下面的命令将下载的.tar.gz文件解压到当前用户的主目录~

Terminal

 % pwd

# In this example, the ${username} is mkyong
/Users/${username}/Downloads

% tar -xvzf apache-maven-3.6.3-bin.tar.gz -C ~        

x apache-maven-3.6.3/README.txt
x apache-maven-3.6.3/LICENSE
x apache-maven-3.6.3/NOTICE
x apache-maven-3.6.3/lib/
#... 

2.3 现在,Maven 文件夹在这个路径/Users/mkyong/apache-maven-3.6.3

Terminal

 % ls -lsa ~/apache-maven-3.6.3

total 64
0 drwxr-xr-x   9 mkyong  staff    288 Jan 14 11:08 .
0 drwxr-xr-x+ 29 mkyong  staff    928 Jan 14 11:08 ..
40 -rw-r--r--   1 mkyong  staff  17504 Nov  7  2019 LICENSE
16 -rw-r--r--   1 mkyong  staff   5141 Nov  7  2019 NOTICE
8 -rw-r--r--   1 mkyong  staff   2612 Nov  7  2019 README.txt
0 drwxr-xr-x   8 mkyong  staff    256 Jan 14 11:08 bin
0 drwxr-xr-x   4 mkyong  staff    128 Nov  7  2019 boot
0 drwxr-xr-x   5 mkyong  staff    160 Nov  7  2019 conf
0 drwxr-xr-x  65 mkyong  staff   2080 Nov  7  2019 lib

% cd ~/apache-maven-3.6.3
% pwd
/Users/mkyong/apache-maven-3.6.3 

2.4 在 macOS 10.5 Catalina 或更高版本上,默认 shell 是 zsh ,我们可以创建环境变量MAVEN_HOME并更新~/.zshenv中的PATH

打开~/.zshenv,追加以下内容。

~/.zshenv

 export MAVEN_HOME=~/apache-maven-3.6.3
export PATH=$PATH:$MAVEN_HOME/bin 

注意
对于 macOS 10.14 Mojave 及之前的版本,默认的终端 shell 是bash,我们可以在~/.bash_profile中创建环境变量。

打开~/.bash_profile,追加以下内容。

~/.bash_profile

 export MAVEN_HOME=~/apache-maven-3.6.3
export PATH=$PATH:$MAVEN_HOME/bin 

P.S 阅读此 Zsh 启动文件

2.5 生成~/.zshenv以反映变化。

Terminal

 % source ~/.zshenv 

2.6 验证。

Terminal

 % mvn -version

Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: /Users/mkyong/apache-maven-3.6.3
Java version: 14, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/jdk-14.jdk/Contents/Home
Default locale: en_MY, platform encoding: UTF-8
OS name: "mac os x", version: "10.16", arch: "x86_64", family: "mac" 

完成了。

参考文献

intellij IDEA–弹簧引导重新加载静态文件不起作用

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/intellij-idea-spring-boot-template-reload-is-not-working/

在 Eclipse 中,只要包含 Spring Boot 开发工具依赖项,热插拔和静态文件重载就会神奇地启用。对于 Intellij IDE,我们需要额外的步骤来启用它。

1.Spring Boot 开发工具

启用 Spring Boot 开发工具后:

  • 对视图或资源的任何更改都可以直接在浏览器中看到,无需重启,只需刷新浏览器。
  • 对代码的任何修改都会自动重启 Spring 容器。

首先,包括Spring Boot Dev Tools依赖项:

pom.xml

 <!-- hot swapping, enable live reload -->
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <optional>true</optional>
  </dependency> 

2.自动构建项目

文件–>设置–>构建、执行、部署–>编译器–>检查此Build project automatically

3.Intellij 注册表

3.1 按SHIFT+CTRL+A (Win/*nix)或Command+SHIFT+A (Mac)打开一个弹出窗口,键入registry

3.2 找到并启用此选项compiler.automake.allow.when.app.running

完成了。现在,热插拔和静态文件自动重新加载应该启用。

In Menu -> Build -> Build Project (CTRL + F9)
If the static files are not reloaded, press CTRL+F9 to force a reload.

参考

Intellij + Infinitest 持续测试

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/intellij/intellij-infinitest-continuous-testing/

Infinitest 是一个持续测试插件,它有助于自动运行测试。

1.在 IntelliJ 上安装

1.1 在插件中,点击“浏览存储库…”

infinitest-idea-1

1.2 键入“Infinitest”并单击“安装”按钮。

infinitest-idea-2

1.3 重启 Intellij IDEA。

2.添加 Infinitest 方面

在项目结构/设置中,添加一个“Infinitest”方面。

infinitest-idea-facet ## 3.启用自动生成项目

3.1 默认情况下,Intellij 不会自动编译类,您需要手动启用它,以便“Infinitest”插件可以检测到变化并自动运行测试。

3.2 在项目设置或首选项中,选择【编译器】-->Make project automatically

idea-build-project-automatically

4.连续测试

搞定,万事俱备,享受持续测试。

Infinitest 插件将在任何项目源代码被更改时运行所有测试类。
*如果一个测试类被修改,Infinitest 插件将自动运行当前修改的测试类。

infinitest-idea-3Note
Please refer to this Infinitest user guide for more tips

参考

  1. Infinitest 官方网站
  2. JetBrains 插件库–Infinitest
  3. Intellij IDEA–如何自动构建项目

idea test

inverse = "true "示例和说明

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/inverse-true-example-and-explanation/

Always put inverse=”true” in your collection variable ?
There are many Hibernate articles try to explain the “inverse” with many Hibernate “official” jargon, which is very hard to understand (at least to me). In few articles, they even suggested that just forget about what is “inverse”, and always put inverse=”true” in the collection variable.

这句话永远是正确的——“在集合变量中放置逆=真”,但是不要对此视而不见,试着理解背后的原因对于优化你的 Hibernate 性能是至关重要的。

什么是“逆”?

这是 Hibernate 中最容易混淆的关键词,至少我花了相当长的时间才理解。关键字在一对多多对多关系中总是声明的(多对一没有逆关键字),表示哪一方负责照顾关系。

“逆”,应该改成“关系主”?

在 Hibernate 中,只有“关系所有者”应该维护关系,创建“反向”关键字来定义哪一方是维护关系的所有者。然而“反向”关键字本身不够详细,我建议将关键字改为“ relationship_owner ”。

简而言之,inverse="true "表示这是关系所有者,inverse="false "(默认)表示不是。

1.一对多关系

这是一个一对多的关系表设计,一个股票表在 STOCK_DAILY_RECORD 表中有多次出现。

one to many relationship

2.Hibernate 实现

请参见 XML 映射文件中的 Hibernate 实现。

文件:Stock.java

 public class Stock implements java.io.Serializable {
   ...
   private Set<StockDailyRecord> stockDailyRecords = 
						new HashSet<StockDailyRecord>(0);
   ... 

文件:StockDailyRecord.java

 public class StockDailyRecord implements java.io.Serializable {
   ...
   private Stock stock;
   ... 

文件:Stock.hbm.xml

 <hibernate-mapping>
    <class name="com.mkyong.common.Stock" table="stock" ...>
    ...
    <set name="stockDailyRecords" table="stock_daily_record" fetch="select">
        <key>
            <column name="STOCK_ID" not-null="true" />
        </key>
        <one-to-many class="com.mkyong.common.StockDailyRecord" />
    </set>
    ... 

文件:StockDailyRecord.hbm.xml

 <hibernate-mapping>
  <class name="com.mkyong.common.StockDailyRecord" table="stock_daily_record" ...>
  ...
  <many-to-one name="stock" class="com.mkyong.common.Stock">
       <column name="STOCK_ID" not-null="true" />
  </many-to-one>
  ... 

3.逆=真/假

Inverse 关键字适用于一对多关系。这里的问题是,如果在“股票”对象中执行保存或更新操作,它是否应该更新“股票每日记录”关系?

文件:Stock.hbm.xml

 <class name="com.mkyong.common.Stock" table="stock" ...>
    ...
    <set name="stockDailyRecords" table="stock_daily_record" inverse="{true/false}" fetch="select">
        <key>
            <column name="STOCK_ID" not-null="true" />
        </key>
        <one-to-many class="com.mkyong.common.StockDailyRecord" />
    </set>
    ... 

1。inverse="true"

如果 set 变量中的 inverse="true ",则表示" stock_daily_record "是关系所有者,因此 stock 不会更新关系。

 <class name="com.mkyong.common.Stock" table="stock" ...>
    ...
	<set name="stockDailyRecords" table="stock_daily_record" inverse="true" > 

2。inverse="false"

如果 set 变量中的 inverse="false "(默认值),则表示“股票”是关系所有者,股票将更新关系。

 <class name="com.mkyong.common.Stock" table="stock" ...>
	...
	<set name="stockDailyRecords" table="stock_daily_record" inverse="false" > 

查看以下更多示例:

4.inverse="false "示例

如果没有定义关键字“inverse ”,将使用 inverse = "false ",即

 <!--Stock.hbm.xml-->
<class name="com.mkyong.common.Stock" table="stock" ...>
	...
	<set name="stockDailyRecords" table="stock_daily_record" inverse="false"> 

这意味着“股票”是关系的所有者,它将维持关系。

插入示例…

当保存一个“股票”对象时,Hibernate 将生成三个 SQL 语句,两个插入和一个更新。

 session.beginTransaction();

    Stock stock = new Stock();
    stock.setStockCode("7052");
    stock.setStockName("PADINI");

    StockDailyRecord stockDailyRecords = new StockDailyRecord();
    stockDailyRecords.setPriceOpen(new Float("1.2"));
    stockDailyRecords.setPriceClose(new Float("1.1"));
    stockDailyRecords.setPriceChange(new Float("10.0"));
    stockDailyRecords.setVolume(3000000L);
    stockDailyRecords.setDate(new Date());

    stockDailyRecords.setStock(stock);        
    stock.getStockDailyRecords().add(stockDailyRecords);

    session.save(stock);
    session.save(stockDailyRecords);

    session.getTransaction().commit(); 

输出…

 Hibernate: 
    insert 
    into
        mkyongdb.stock
        (STOCK_CODE, STOCK_NAME) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        mkyongdb.stock_daily_record
        (STOCK_ID, PRICE_OPEN, PRICE_CLOSE, PRICE_CHANGE, VOLUME, DATE) 
    values
        (?, ?, ?, ?, ?, ?)
Hibernate: 
    update
        mkyongdb.stock_daily_record 
    set
        STOCK_ID=? 
    where
        RECORD_ID=? 

股票将更新"股票 _ 日报 _ 记录。STOCK_ID "通过设置变量(stockDailyRecords),因为 STOCK 是关系所有者。

Note
The third statement is really NOT necessary.

更新示例…

当一个“股票”对象被更新时,Hibernate 将生成两条 SQL 语句,一条插入,一条更新。

 session.beginTransaction();

    Stock stock = (Stock)session.get(Stock.class, 57);

    StockDailyRecord stockDailyRecords = new StockDailyRecord();
    stockDailyRecords.setPriceOpen(new Float("1.2"));
    stockDailyRecords.setPriceClose(new Float("1.1"));
    stockDailyRecords.setPriceChange(new Float("10.0"));
    stockDailyRecords.setVolume(3000000L);
    stockDailyRecords.setDate(new Date());

    stockDailyRecords.setStock(stock);        
    stock.getStockDailyRecords().add(stockDailyRecords);

    session.save(stockDailyRecords);
    session.update(stock);

    session.getTransaction().commit(); 

输出…

 Hibernate: 
    insert 
    into
        mkyongdb.stock_daily_record
        (STOCK_ID, PRICE_OPEN, PRICE_CLOSE, PRICE_CHANGE, VOLUME, DATE) 
    values
        (?, ?, ?, ?, ?, ?)
Hibernate: 
    update
        mkyongdb.stock_daily_record 
    set
        STOCK_ID=? 
    where
        RECORD_ID=? 

Note
Again, the third statement is NOT necessary.

5.inverse="true "示例

如果定义了关键字“逆=真”:

 <!--Stock.hbm.xml-->
<class name="com.mkyong.common.Stock" table="stock" ...>
	...
	<set name="stockDailyRecords" table="stock_daily_record" inverse="true"> 

现在,它的意思是" stockDailyRecords "是关系所有者,而" stock "不会维护关系。

插入示例…

当保存一个“股票”对象时,Hibernate 会生成两条 SQL insert 语句。

 session.beginTransaction();

    Stock stock = new Stock();
    stock.setStockCode("7052");
    stock.setStockName("PADINI");

    StockDailyRecord stockDailyRecords = new StockDailyRecord();
    stockDailyRecords.setPriceOpen(new Float("1.2"));
    stockDailyRecords.setPriceClose(new Float("1.1"));
    stockDailyRecords.setPriceChange(new Float("10.0"));
    stockDailyRecords.setVolume(3000000L);
    stockDailyRecords.setDate(new Date());

    stockDailyRecords.setStock(stock);        
    stock.getStockDailyRecords().add(stockDailyRecords);

    session.save(stock);
    session.save(stockDailyRecords);

    session.getTransaction().commit(); 

输出…

 Hibernate: 
    insert 
    into
        mkyongdb.stock
        (STOCK_CODE, STOCK_NAME) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        mkyongdb.stock_daily_record
        (STOCK_ID, PRICE_OPEN, PRICE_CLOSE, PRICE_CHANGE, VOLUME, DATE) 
    values
        (?, ?, ?, ?, ?, ?) 

更新示例…

当一个“股票”对象被更新时,Hibernate 将生成一条 SQL 语句。

 session.beginTransaction();

    Stock stock = (Stock)session.get(Stock.class, 57);

    StockDailyRecord stockDailyRecords = new StockDailyRecord();
    stockDailyRecords.setPriceOpen(new Float("1.2"));
    stockDailyRecords.setPriceClose(new Float("1.1"));
    stockDailyRecords.setPriceChange(new Float("10.0"));
    stockDailyRecords.setVolume(3000000L);
    stockDailyRecords.setDate(new Date());

    stockDailyRecords.setStock(stock);        
    stock.getStockDailyRecords().add(stockDailyRecords);

    session.save(stockDailyRecords);
    session.update(stock);

    session.getTransaction().commit(); 

输出…

 Hibernate: 
    insert 
    into
        mkyongdb.stock_daily_record
        (STOCK_ID, PRICE_OPEN, PRICE_CLOSE, PRICE_CHANGE, VOLUME, DATE) 
    values
        (?, ?, ?, ?, ?, ?) 

inverse vs cascade
Many people like to compare between inverse and cascade, but both are totally different notions, see the differential here.

结论

理解“逆”对于优化 Hibernate 代码至关重要,它有助于避免许多不必要的更新语句,如上面的“insert and update example for inverse = false”。最后,试着记住逆=“真”的意思,这是关系所有者处理关系。

参考

  1. http://simoes.org/docs/hibernate-2.1/155.html
  2. http://docs . JBoss . org/hibernate/stable/core/reference/en/html/example-parent child . html
  3. http://tad tech . blogspot . com/2007/02/hibernate-when-is-inverse true-and-when . html

Tags : hibernate

相关文章

Jackson 2–将 Java 对象转换成 JSON 从 JSON 转换过来

原文:http://web.archive.org/web/20230101150211/https://www.mkyong.com/java/jackson-2-convert-java-object-to-from-json/

在本教程中,我们将向您展示如何使用 Jackson 2.x 在 Java 对象和 JSON 之间进行转换。

1.基础

1.1 将一个Staff对象转换成 from JSON。

writeValue(...)–Java 对象到 JSON

 ObjectMapper mapper = new ObjectMapper();

	// Java object to JSON file
	mapper.writeValue(new File("c:\\test\\staff.json"), new Staff());

	// Java object to JSON string
	String jsonString = mapper.writeValueAsString(object); 

readValue(...)–JSON 到 Java 对象

 ObjectMapper mapper = new ObjectMapper();

	//JSON file to Java object
	Staff obj = mapper.readValue(new File("c:\\test\\staff.json"), Staff.class);

	//JSON URL to Java object
	Staff obj = mapper.readValue(new URL("http://some-domains/api/name.json"), Staff.class);

	//JSON string to Java Object
	Staff obj = mapper.readValue("{'name' : 'mkyong'}", Staff.class); 

用杰克逊 2.9.8 测试的 PS

Note
Read this How to parse JSON with Jackson, containing Jackson examples like Object to/from JSON, @JsonView, @JsonProperty, @JsonInclude, @JsonIgnore, and some FAQs.

1.下载杰克逊

1.1 声明jackson-databind,将拉入jackson-annotationsjackson-core

pom.xml

 <dependency>
		<groupId>com.fasterxml.jackson.core</groupId>
		<artifactId>jackson-databind</artifactId>
		<version>2.9.8</version>
	</dependency> 

1.2 回顾杰克逊依赖关系:

Terminal

 $ mvn dependency:tree

\- com.fasterxml.jackson.core:jackson-databind:jar:2.9.8:compile
[INFO]    +- com.fasterxml.jackson.core:jackson-annotations:jar:2.9.0:compile
[INFO]    \- com.fasterxml.jackson.core:jackson-core:jar:2.9.8:compile 

Difference between Jackson 1 and Jackson 2
Most of the APIs still maintains the same method name and signature, just the packaging is different.

  • 杰克逊 1 . x–org . code Haus . Jackson . map
  • Jackson 2 . x–com . faster XML . Jackson . databind

2.波乔

用于测试的简单 Java 对象。

Staff.java

 public class Staff {

    private String name;
    private int age;
    private String[] position;              //  Array
    private List<String> skills;            //  List
    private Map<String, BigDecimal> salary; //  Map

	// getters , setters, some boring stuff
} 

3.JSON 的 Java 对象

JacksonExample1.java

 package com.mkyong;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class JacksonExample1 {

    public static void main(String[] args) {

        ObjectMapper mapper = new ObjectMapper();

        Staff staff = createStaff();

        try {

            // Java objects to JSON file
            mapper.writeValue(new File("c:\\test\\staff.json"), staff);

            // Java objects to JSON string - compact-print
            String jsonString = mapper.writeValueAsString(staff);

            System.out.println(jsonString);

            // Java objects to JSON string - pretty-print
            String jsonInString2 = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(staff);

            System.out.println(jsonInString2);

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private static Staff createStaff() {

        Staff staff = new Staff();

        staff.setName("mkyong");
        staff.setAge(38);
        staff.setPosition(new String[]{"Founder", "CTO", "Writer"});
        Map<String, BigDecimal> salary = new HashMap() {{
            put("2010", new BigDecimal(10000));
            put("2012", new BigDecimal(12000));
            put("2018", new BigDecimal(14000));
        }};
        staff.setSalary(salary);
        staff.setSkills(Arrays.asList("java", "python", "node", "kotlin"));

        return staff;

    }

} 

输出

c:\test\staff.json

 {"name":"mkyong","age":38,"position":["Founder","CTO","Writer"],"skills":["java","python","node","kotlin"],"salary":{"2018":14000,"2012":12000,"2010":10000}} 

Terminal

 {"name":"mkyong","age":38,"position":["Founder","CTO","Writer"],"skills":["java","python","node","kotlin"],"salary":{"2018":14000,"2012":12000,"2010":10000}}

{
  "name" : "mkyong",
  "age" : 38,
  "position" : [ "Founder", "CTO", "Writer" ],
  "skills" : [ "java", "python", "node", "kotlin" ],
  "salary" : {
    "2018" : 14000,
    "2012" : 12000,
    "2010" : 10000
  }
} 

4.JSON 到 Java 对象

JacksonExample2.java

 package com.mkyong;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.File;
import java.io.IOException;

public class JacksonExample2 {

    public static void main(String[] args) {

        ObjectMapper mapper = new ObjectMapper();

        try {

            // JSON file to Java object
            Staff staff = mapper.readValue(new File("c:\\test\\staff.json"), Staff.class);

            // JSON string to Java object
            String jsonInString = "{\"name\":\"mkyong\",\"age\":37,\"skills\":[\"java\",\"python\"]}";
            Staff staff2 = mapper.readValue(jsonInString, Staff.class);

            // compact print
            System.out.println(staff2);

            // pretty print
            String prettyStaff1 = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(staff2);

            System.out.println(prettyStaff1);

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

} 

输出

 Staff{name='mkyong', age=37, position=null, skills=[java, python], salary=null}

{
  "name" : "mkyong",
  "age" : 37,
  "position" : null,
  "skills" : [ "java", "python" ],
  "salary" : null
} 

Note
More Jackson examples read this – How to parse JSON with Jackson

参考

posted @   绝不原创的飞龙  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
点击右上角即可分享
微信分享提示