Logging API, Resource Bundles, Networking trong Java
- 26-01-2024
- Toanngo92
- 0 Comments
Mục lục
Tổng quan về Log4J
Log4J là một framework ghi nhật ký mã nguồn mở cho các ứng dụng Java. Nó cho phép tạo ra các thông báo nhật ký từ các phần khác nhau của ứng dụng. Những thông báo nhật ký này hỗ trợ trong việc gỡ lỗi ứng dụng để phát hiện lỗi và theo dõi luồng thực thi. Log4J gán các cấp độ quan trọng khác nhau, chẳng hạn như ERROR, WARN, INFO và DEBUG cho các thông báo nhật ký. Với Log4J, các thông báo nhật ký có thể được định tuyến đến các loại đích khác nhau, như console, tệp, và cơ sở dữ liệu.
Kiến trúc Log4J bao gồm ba thành phần chính:
- Loggers
- Appenders
- Layouts
Loggers, Appender và Layout của nó
Logger là thành phần chính của Log4J có trách nhiệm ghi nhật ký các thông báo. Nhà phát triển có thể tạo ra logger cụ thể cho ứng dụng của họ hoặc sử dụng logger gốc được cung cấp bởi Log4J. Tất cả các logger của Log4J đều kế thừa từ logger gốc. Do đó, mỗi khi một đoạn mã ghi lại một thông báo, Log4J tìm kiếm logger cụ thể cho ứng dụng. Nếu không tìm thấy, Log4J sử dụng logger gốc.
Trong một ứng dụng, logger gốc có thể được khởi tạo và lấy bằng cách gọi phương thức LoggerManager.getRootLogger()
. Logger của ứng dụng có thể được khởi tạo và lấy bằng cách gọi phương thức LoggerManager.getLogger(String loggerName)
, chấp nhận tên của logger mong muốn như một tham số. Mặc dù bất kỳ tên nào cũng có thể được truyền vào phương thức getLogger()
dưới dạng một chuỗi, nhưng nên đặt tên cho logger bằng tên đầy đủ của lớp sẽ thực hiện ghi nhật ký.
Logger được gán các cấp độ nhật ký, trong đó TRACE là cấp độ thấp nhất. Các cấp độ di chuyển lên từ TRACE qua DEBUG, INFO, WARN và ERROR, cho đến cấp độ FATAL cao nhất.
Khi một cấp độ cao hơn được gán cho một logger, tất cả các thông báo nhật ký của cấp độ đó và các cấp độ dưới đó sẽ được ghi lại. Ví dụ, nếu cấp độ INFO được gán cho một logger, thì các thông báo INFO, DEBUG và TRACE sẽ được ghi lại.
Layouts xác định cách thông báo nhật ký được định dạng trong đích đầu ra và chúng được liên kết với các appenders. Trước khi appender gửi một thông báo nhật ký đến đích đầu ra, nó sử dụng layout liên kết để định dạng thông báo nhật ký.
Log4J cung cấp các lớp bố trí tích hợp sẵn, chẳng hạn như PatternLayout, HtmlLayout, JsonLayout và XmlLayout. Log4J cũng hỗ trợ các bố trí tùy chỉnh có thể được tạo ra bằng cách mở rộng lớp trừu tượng AbstractStringLayout.
Sử dụng Log4J
Đối với mỗi cấp độ nhật ký, Log4J xác định một phương thức nhật ký tương ứng. Bảng 13.1 liệt kê các phương thức nhật ký của Log4J.
Phương thức | Mô tả |
---|---|
trace() | Ghi nhật ký một phương thức với cấp độ TRACE. |
debug() | Ghi nhật ký một phương thức với cấp độ DEBUG. |
info() | Ghi nhật ký một phương thức với cấp độ INFO. |
warn() | Ghi nhật ký một phương thức với cấp độ WARN. |
error() | Ghi nhật ký một phương thức với cấp độ ERROR. |
fatal() | Ghi nhật ký một phương thức với cấp độ FATAL. |
keyset() | Trả về một Set chứa tất cả các khóa trong ResourceBundle |
Tạo Logging cho ứng dụng
Log4J là mã nguồn mở và có thể được tải về miễn phí. Nếu bạn đang tạo một dự án Java Maven, bạn không cần phải tải về các tệp Log4J vì chúng có sẵn trong kho Maven. Bạn chỉ cần thêm các phụ thuộc. Cách thực hiện:
- Mở Apache NetBeans.
- Tạo một dự án ứng dụng Java Maven với tên Log4JDemo.
- Trong cửa sổ Dự án, tìm và mở tệp pom.xml.
Cập nhật package log4j vào file pom.xml của dự án:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>logging</groupId>
<artifactId>loggingdemo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>15</maven.compiler.source>
<maven.compiler.target>15</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.13.0</version>
</dependency>
</dependencies>
</project>
Ví dụ sử dụng log4j:
package com.log4jdemo;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class LoggerDemo {
private static final Logger logger = LogManager.getLogger(LoggerDemo.class);
public void performLogging() {
logger.debug("This is a debug message");
logger.info("This is an info message");
logger.warn("This is a warn message");
logger.error("This is an error message");
logger.fatal("This is a fatal message");
}
public static void main(String[] args) {
LoggerDemo loggerDemo = new LoggerDemo();
loggerDemo.performLogging();
}
}
Hiện tại, ứng dụng sẽ trả ra lỗi vì chưa có tệp cấu hình, tuy nhiên nếu cấu hình chuẩn, output sẽ trả ra như nội dung dưới đây.
Output:
0 [main] DEBUG com.log4jdemo.LoggerDemo - This is a debug message
0 [main] INFO com.log4jdemo.LoggerDemo - This is an info message
0 [main] WARN com.log4jdemo.LoggerDemo - This is a warn message
0 [main] ERROR com.log4jdemo.LoggerDemo - This is an error message
0 [main] FATAL com.log4jdemo.LoggerDemo - This is a fatal message
Cấu hình Tệp Thuộc tính
Tệp cấu hình thuộc tính của Log4J chứa các cặp khóa-giá trị chỉ định các tùy chọn cấu hình ghi nhật ký. Theo mặc định, Log4J mong đợi một tệp thuộc tính có tên log4j2.properties trong đường dẫn lớp dự án. Trong một dự án ứng dụng Java NetBeans, tệp log4j2.properties nên nằm trong thư mục src.
Nội dung tệp:
# Set the root logger level to DEBUG
log4j.rootLogger=DEBUG, STDOUT
# Define the console appender
log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender
log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout
log4j.appender.STDOUT.layout.ConversionPattern=%-5p:%d{1}:%L - %m%n
# Set the root logger to use the console appender
log4j.rootLogger=debug, STDOUT
Đặt tệp này trong thư mục src\main
của dự án ứng dụng của bạn trong NetBeans.
Cấu hình file XML
Log4J cũng hỗ trợ cấu hình thông qua tệp XML. Tương tự như tệp thuộc tính, một tệp log4j2.xml phải có mặt trong đường dẫn lớp dự án.
Mô tả một tệp cấu hình log4j2.xml.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration name="PropertiesConfig">
<Appenders>
<Console name="consoleappender" target="STDOUT">
<PatternLayout>
<Pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %p %c{1.} - %m%n
</Pattern>
</PatternLayout>
</Console>
</Appenders>
<Loggers>
<Root level="DEBUG">
<AppenderRef ref="consoleappender"/>
</Root>
</Loggers>
</Configuration>
Trong cấu hình XML này:
- Phần tử
<Configuration>
chỉ định tên của cấu hình. - Phần
<Appenders>
xác định các appenders, và trong trường hợp này, nó bao gồm một appender console. - Phần tử
<Console>
cấu hình appender console. <PatternLayout>
chỉ định mẫu layout cho các thông báo nhật ký.- Phần
<Root>
cấu hình root logger với cấp độ DEBUG và liên kết nó với appender console.
Đảm bảo bạn đặt tệp log4j2.xml trong đường dẫn lớp dự án.
File Appender
Một tệp cấu hình XML của Log4J chứa phần tử gốc <Configuration>
.
Phần tử <Appenders>
chứa một phần tử <Console>
để cấu hình appender của console. Phần tử <PatternLayout>
chỉ định mẫu layout sử dụng với appender, và phần tử <Pattern>
chỉ định mẫu định dạng sử dụng. Phần tử <Loggers>
chứa phần tử <Root>
để cấu hình root logger. Thuộc tính level
của phần tử <Root>
gán cấp độ log DEBUG cho root logger. Cuối cùng, thuộc tính ref
của phần tử <AppenderRef>
gán appender console cho root logger. Cấu hình XML này thực hiện chức năng tương tự như cấu hình thuộc tính được đưa ra trong đoạn mã phá trên.
Bộ appender file được sử dụng để gửi các thông báo nhật ký đến một tệp. Bộ appender file có thể được cấu hình bằng phần tử <File>
trong một tệp cấu hình XML.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<File name="fileappender" fileName="logs/logfile.log">
<PatternLayout>
<Pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %p %c{1.} - %m%n
</Pattern>
</PatternLayout>
</File>
</Appenders>
<Loggers>
<Root level="DEBUG">
<AppenderRef ref="fileappender"/>
</Root>
</Loggers>
</Configuration>
Mã, khi thực thi lớp LoggerDemo
được đưa ra trong đoạn mã phía trên, sẽ tạo ra một tệp nhật ký có tên là “logfile.log” chứa các thông báo nhật ký trong thư mục “applogs”. Thư mục “applogs” sẽ được tạo trong thư mục gốc của dự án.
JDBC Appender
Bộ Appender JDBC hỗ trợ lưu trữ các thông báo nhật ký trong một bảng cơ sở dữ liệu. Phần tử <JDBC>
cấu hình bộ appender JDBC. Để sử dụng bộ appender JDBC, bạn cần các thông tin bắt buộc sau:
- URL kết nối đến cơ sở dữ liệu
- Tên bảng cơ sở dữ liệu để lưu trữ các thông báo nhật ký
- Các cột trong bảng để ghi các thông báo nhật ký
Để sử dụng bộ appender JDBC, cần có một máy chủ cơ sở dữ liệu quan hệ. Một trong những cơ sở dữ liệu phổ biến được sử dụng cho ứng dụng Java là MySQL. Bạn có thể tải MySQL từ liên kết sau:
Sau khi cài đặt MySQL, bạn cần tạo một cơ sở dữ liệu và một bảng trong đó để lưu trữ thông tin nhật ký.
Xem thêm bài viết này nếu bạn chưa nắm rõ về JDBC:
Mã tạo database:
-- Create the database
CREATE DATABASE IF NOT EXISTS LOG4sL0G;
-- Switch to the created database
USE LOG4sL0G;
-- Create the table for application logs
CREATE TABLE IF NOT EXISTS applicationlog (
ID VARCHAR(100),
LEVEL VARCHAR(100),
LOGGER VARCHAR(100),
MESSAGE VARCHAR(100)
);
Lớp ResourceBundle
Lớp ResourceBundle
trong gói java.util
cho phép tạo các chương trình hỗ trợ đa ngôn ngữ có thể hiển thị giao diện người dùng và đầu ra bằng các ngôn ngữ khác nhau. Một đối tượng của lớp ResourceBundle
đại diện cho thông tin phụ thuộc vào vùng địa phương. Khi một chương trình yêu cầu một nguồn tài nguyên cụ thể cho vùng địa phương, ví dụ, một String
, chương trình sẽ tải nó từ gói tài nguyên dựa trên vùng địa phương hiện tại của người dùng.
Các lớp PropertyResourceBundle
và ListResourceBundle
mở rộng từ ResourceBundle
. PropertyResourceBundle
là một lớp cụ thể để đại diện cho thông tin phụ thuộc vào vùng địa phương được lưu trữ dưới dạng cặp khóa-giá trị trong các tệp thuộc tính. Ngược lại, ListResourceBundle
là một lớp trừu tượng để đại diện cho thông tin phụ thuộc vào vùng địa phương được lưu trữ trong các bộ sưu tập dựa trên danh sách.
Chương trình Java không tương tác trực tiếp với các lớp PropertyResourceBundle
và ListResourceBundle
. Mọi tương tác của chương trình đều thông qua lớp ResourceBundle
. Lớp ResourceBundle
có một bộ điều khiển mặc định duy nhất. Tuy nhiên, có nhiều phương thức mà chương trình có thể sử dụng để tạo một ResourceBundle
và tương tác với các nguồn tài nguyên cụ thể cho từng vùng địa phương.
Các Phương thức:
Các phương thức chính có sẵn trong lớp ResourceBundle
.
Phương thức | Mô tả |
---|---|
getBundle() | Trả về một đối tượng ResourceBundle cho vùng địa phương mặc định. Phiên bản quá tải của phương thức này chấp nhận một đối tượng Locale để trả về một đối tượng ResourceBundle cho vùng địa phương được chỉ định. |
getLocale() | Trả về vùng địa phương hiện tại của người dùng. |
getObject(String key) | Trả về đối tượng tương ứng với khóa từ gói tài nguyên. |
clearCache() | Xóa bộ nhớ cache của tất cả các gói tài nguyên đã được tải bởi class loader. |
containsKey(String key) | Kiểm tra xem khóa cụ thể có tồn tại trong gói tài nguyên hay không. |
getKeys() | Trả về một Enumeration của tất cả các khóa trong gói tài nguyên. |
keySet() | Trả về một Set của tất cả các khóa trong ResourceBundle . |
Công cụ Javadoc và Tài liệu trong Java
Công cụ Javadoc cho phép tạo tài liệu API dựa trên HTML từ mã nguồn Java. Javadoc phụ thuộc vào các thẻ tài liệu có sẵn trong mã nguồn. Công cụ này có thể được sử dụng để tạo tài liệu cho các gói, lớp, giao diện, phương thức và trường.
API Java là một bộ sưu tập lớn các loại, trong đó mỗi loại có thể có một số lượng lớn các cấu trúc như constructor, trường và phương thức. Để sử dụng hiệu quả API Java, nhà phát triển cần biết về mục đích của các loại và cấu trúc của chúng. Thông tin này được cung cấp thông qua tài liệu API.
Trong quá trình phát triển ứng dụng và thư viện, nhà phát triển Java cũng cần cung cấp tài liệu cho các lớp và cấu trúc của chúng. Mục tiêu là mô tả mọi thứ mà một nhà phát triển khác có thể cần để sử dụng API. Ví dụ, tài liệu API của một phương thức thường cung cấp thông tin về nhiệm vụ của phương thức, quyền truy cập, tham số, kiểu trả về và bất kỳ ngoại lệ nào có thể xảy ra. Thông tin như vậy có thể giúp những nhà phát triển khác hiểu được đã làm gì và tại sao đã làm, khi duyệt qua mã nguồn.
Trong Java, tài liệu API được tạo bằng cách sử dụng các thẻ tài liệu. Dựa trên các thẻ này, công cụ Javadoc sẽ tạo ra tài liệu API dưới dạng HTML. Công cụ này được tự động cài đặt như một phần của Java SDK và có thể được tìm thấy trong thư mục bin của đường dẫn JDK. Các công cụ IDE như Eclipse và NetBeans cũng hỗ trợ Javadoc.
Thẻ Javadoc:
Các thẻ Javadoc có thể chia thành chủ yếu là thẻ ở cấp lớp và cấp phương thức.
Thẻ Cấp Lớp
Bảng dưới giải thích về các thẻ cấp lớp.
Thẻ | Mô Tả |
---|---|
@author | Chèn tên tác giả của lớp. |
@code | Chèn văn bản trong định dạng mã nguồn. |
@see | Chèn một tiêu đề “See Also” với một liên kết hoặc nhập văn bản trỏ đến tài liệu liên quan một cách chặt chẽ. |
@since | Chèn một tiêu đề “Since” được sử dụng để chỉ định từ khi lớp này tồn tại. |
@deprecated | Chèn một ý kiến để biểu thị rằng lớp này đã lỗi thời và không nên được sử dụng nữa. |
Đối với mỗi thẻ, chúng ta có một mô tả về cách nó được sử dụng để tạo tài liệu Javadoc.
Ví dụ:
/**
* MathDemo class provides a demonstration of mathematical operations.
*
* @author Carl Boynton
* @author Andy Payne
* @see Collection
* @see Vector
* @since JDK 1.0
*/
public class MathDemo {
// Code implementation goes here
}
Ở ví dụ trên, lớp MathDemo
sẽ có thông tin chỉ ra người là tác giả của mã nguồn, các lớp nào nên được xem thêm, và từ phiên bản nào mà lớp đã tồn tại.
Thẻ Cấp Phương Thức
Bảng dưới giải thích về các thẻ cấp phương thức.
Thẻ | Mô Tả |
---|---|
@param | Chèn một tham số mà phương thức chấp nhận. |
@return | Chèn kiểu trả về của phương thức. |
@throws | Chèn bất kỳ ngoại lệ nào mà phương thức có thể ném ra. |
@see | Chèn một tiêu đề “See Also” với một liên kết hoặc nhập văn bản trỏ đến các phương thức liên quan một cách chặt chẽ. |
@since | Chèn một tiêu đề “Since” với một văn bản để chỉ định từ khi phương thức này tồn tại. |
@deprecated | Chèn một ý kiến để biểu thị rằng phương thức này đã lỗi thời và không nên được sử dụng nữa. |
Đối với mỗi thẻ, chúng ta có một mô tả về cách nó được sử dụng để tạo tài liệu Javadoc.
Ví dụ:
/**
* This method adds two integers.
*
* @param num1 This is the first parameter to the addInt method.
* @param num2 This is the second parameter to the addInt method.
* @return int This returns the sum of num1 and num2.
* @see MathDemo#addition(long, long)
*/
public int addInt(int num1, int num2) {
return num1 + num2;
}
Chú thích @see
trong mã nguồn chỉ định một phương thức addLong(long, long)
trong lớp MathDemo
. Phương thức này phải được định nghĩa trong lớp MathDemo
, nếu không, công cụ Javadoc sẽ báo lỗi biên dịch. Ngoài các thẻ Javadoc, tài liệu API Java còn có thể chứa văn bản để giải thích về một lớp hoặc các cấu trúc của nó. Những văn bản như vậy phải được bao gồm trong các chú thích tài liệu.
Đoạn mã dưới hiển thị một ví dụ hoàn chỉnh mô tả cách sử dụng các thẻ Javadoc và chú thích tài liệu.
/**
* The {@code MathDemo} class implements a calculation algorithm to add two integers.
*
* @author Carl Boynton
* @author Andy Payne
* @see Math
* @since JDK 8.0
*/
public class MathDemo {
/**
* Constructs a MathDemo instance.
*/
public MathDemo() {
}
/**
* This method is used to add two long integers.
*
* @param num1 This is the first parameter to the addLong method.
* @param num2 This is the second parameter to the addLong method.
* @return long This returns the sum of num1 and num2.
*/
public long addLong(long num1, long num2) {
return num1 + num2;
}
/**
* This method is used to add two integers.
*
* @param num1 This is the first parameter to the addInt method.
* @param num2 This is the second parameter to the addInt method.
* @return int This returns the sum of num1 and num2.
*/
public int addInt(int num1, int num2) {
return num1 + num2;
}
/**
* This is the main method to use the addInt method.
*
* @param args Unused.
* @throws java.io.IOException on input error.
* @see java.io.IOException
*/
public static void main(String[] args) throws java.io.IOException {
MathDemo mathDemo = new MathDemo();
System.out.println(mathDemo.addInt(5, 8));
}
}
Bạn có thể tạo tài liệu Java cho đoạn mã này bằng một trong hai cách: Tại dòng lệnh bằng công cụ Javadoc HOẶC bằng cách sử dụng tùy chọn của IDE. Xem xét cách tiếp cận đầu tiên. Bạn sẽ nhập một lệnh như sau tại dòng lệnh:
javadoc MathDemo.java
Nó sẽ tạo ra một tệp HTML chứa tài liệu được tạo ra từ Javadoc. Hình dưới hiển thị tài liệu được tạo ra từ Javadoc được mở trong trình duyệt.
Tùy chọn thứ hai để tạo Javadoc là sử dụng các tính năng tạo Javadoc của một Môi trường Phát triển Tích hợp (IDE), như NetBeans. NetBeans hỗ trợ tự động chèn các chú thích và thẻ Javadoc, tạo tài liệu Javadoc và xem tài liệu Javadoc.
NetBeans hỗ trợ việc viết Javadoc thông qua gợi ý và tính năng hoàn thành mã nguồn. Với tính năng hoàn thành mã nguồn, các chú thích Javadoc cơ bản có thể tự động được tạo ra trong các tệp nguồn. Để tạo một khối chú thích Javadoc, ví dụ, nhập /**
và nhấn TAB và ENTER sẽ tự động tạo ra khối chú thích.
Khi tạo chú thích cho một phương thức, nhập /**
và nhấn TAB và ENTER sẽ thêm vào đó các thẻ @param
và @return
tùy thuộc vào số lượng và kiểu tham số, cũng như kiểu trả về của phương thức đang được tạo tài liệu. Đối với các thẻ khác, một gợi ý xuất hiện dưới dạng cửa sổ bật lên khi nhập một thẻ Javadoc. Bằng cách nhấp vào một thẻ hoặc nhấn ENTER, thẻ sẽ được chèn vào tệp nguồn.
Hình dưới mô phỏng Javadoc tự động hoàn thiện code:
(Khi bạn đã tài liệu hóa một lớp Java, bạn có thể dễ dàng tạo tài liệu của lớp bằng cách sử dụng công cụ Javadoc tích hợp của NetBeans. Để tạo tài liệu Javadoc, mở lớp trong NetBeans. Sau đó, chọn Run > Generate Javadoc từ menu chính của NetBeans, như được thể hiện trong hình dưới:
NetBeans tạo ra tài liệu Javadoc trong thư mục dist/javadoc của thư mục dự án.
Sau khi Javadoc được tạo, nó có thể được xem trên trình duyệt. Để xem tài liệu của một lớp, chuột phải vào lớp trong trình soạn thảo mã nguồn và sau đó chọn Hiển thị Javadoc từ menu ngữ cảnh như hình:
Trình duyệt sẽ hiển thị tài liệu như hình:
Gói java.net
Gói java.net chứa các lớp và giao diện cho lập trình mạng. Sử dụng gói java.net, nhà phát triển có thể tạo ứng dụng giao tiếp qua mạng theo mô hình client-server. Gói này bao gồm các lớp chuyên biệt để tạo socket client và server ở tầng truyền tải cũng như thực hiện giao tiếp qua Internet.
Một số lớp quan trọng của gói java.net như sau:
DatagramPacket
DatagramSocket
Socket
ServerSocket
InetAddress
URL
URLConnection
Lớp DatagramPacket
Lớp DatagramPacket
đại diện cho các gói dữ liệu (datagram) được sử dụng cho việc giao tiếp bằng giao thức User Datagram Protocol (UDP). Giao thức UDP là một giao thức tầng truyền dữ liệu nhẹ được sử dụng để gửi dữ liệu mà không yêu cầu thiết lập kết nối, còn được biết đến là gói dữ liệu (datagram). Một gói datagram chứa thông tin về chính nó và đích đến của nó, dựa trên đó gói được chuyển từ nguồn đến đích. Các gói datagram có thể được định tuyến theo các đường khác nhau. Ngoài ra, UDP không đảm bảo việc chuyển giao gói datagram và rằng chúng sẽ đến theo một thứ tự cụ thể.
Lưu ý: Một đối tượng DatagramPacket
có thể có kích thước tối đa là 65507 byte.
Bảng dưới giải thích về các phương thức của lớp DatagramPacket
.
Phương Thức | Mô Tả |
---|---|
setData(byte[] buf) | Đặt dữ liệu của một gói là một mảng byte. |
setAddress(InetAddress addr) | Đặt địa chỉ IP của máy tính mà một gói datagram phải được gửi đến. |
setLength(int length) | Đặt độ dài của một gói là một giá trị int. |
getData() | Trả về dữ liệu của gói dưới dạng một mảng byte. |
getLength() | Trả về độ dài của dữ liệu trong một gói cần được gửi hoặc trong một gói đã được nhận. |
getAddress() | Trả về địa chỉ IP của máy tính mà một gói datagram được gửi đến hoặc máy tính gửi một gói datagram. |
Lớp DatagramSocket
Lớp DatagramSocket
có trách nhiệm gửi và nhận các gói datagram dưới dạng các đối tượng DatagramPacket
.
Bảng dưới giải thích về các phương thức của lớp DatagramSocket
.
Phương Thức | Mô Tả |
---|---|
connect(InetAddress address, int port) | Kết nối socket đến địa chỉ IP và cổng của một máy từ xa. |
disconnect() | Ngắt kết nối của socket. |
send(DatagramPacket packet) | Gửi một đối tượng DatagramPacket đến một đích. |
receive(DatagramPacket packet) | Nhận một đối tượng DatagramPacket . |
Lớp Socket
Lớp Socket
đại diện cho ổ cắm được sử dụng cả bởi client và server để giao tiếp dữ liệu. Lớp Socket
được sử dụng cho giao tiếp qua giao thức Transmission Control Protocol (TCP). Tương tự như UDP, TCP là một giao thức tầng truyền dữ liệu. TCP đặt ở trên giao thức Internet Protocol (IP), và do đó, cũng được gọi là TCP/IP.
Tuy nhiên, khác với UDP, TCP duy trì một kết nối giữa các điểm cuối mà đối tượng Socket
đại diện. Cả trong client và server, đối tượng Socket
được sử dụng để gửi và nhận các gói TCP. Khác với UDP, không đảm bảo việc gửi và nhận gói, TCP đảm bảo cả hai vì cả socket của client và server vẫn kết nối. Do chi phí duy trì kết nối, TCP chậm hơn UDP.
Để truyền dữ liệu đến một server, một client tạo một đối tượng của lớp Socket
. Tuy nhiên, server không bao giờ khởi tạo một Socket
. Server có được một đối tượng Socket
bằng cách gọi phương thức accept()
của lớp ServerSocket
.
Một client có thể tạo 2 đối tượng Socket
để đại diện cho 2 kết nối đến server bằng cách gọi hàm tạo Socket(String host, int port)
của lớp Socket
. Trong hàm tạo này, tham số đầu tiên chỉ định địa chỉ IP của server và tham số thứ hai chỉ định số cổng mà server lắng nghe tin nhắn.
Bảng dưới giải thích về các phương thức chính của lớp Socket
.
Phương Thức | Mô Tả |
---|---|
connect(SocketAddress host, int timeout) | Kết nối ổ cắm của client với ổ cắm của server. Phương thức này là bắt buộc nếu một đối tượng socket được tạo mà không khởi tạo nó với một kết nối đến server. |
getInputStream() | Trả về một đối tượng InputStream của Socket . Cả client và server đều sử dụng phương thức getInputStream() để nhận dữ liệu. |
getOutputStream() | Trả về một đối tượng OutputStream của Socket . Cả client và server đều sử dụng phương thức getOutputStream() để gửi dữ liệu. |
close() | Đóng kết nối của Socket . |
Lớp ServerSocket
Lớp ServerSocket
được sử dụng bởi các server để lắng nghe các kết nối đến từ các client. Thông thường, một server gọi hàm tạo ServerSocket(String port)
để khởi tạo một đối tượng ServerSocket
. Sau khi server có được đối tượng ServerSocket
, server có thể gọi các phương thức của ServerSocket
để chấp nhận các kết nối và lấy thông tin về đối tượng ServerSocket
.
Bảng dưới giải thích về các phương thức chính của lớp ServerSocket
.
Phương Thức | Mô Tả |
---|---|
bind(SocketAddress endPoint) | Liên kết một đối tượng ServerSocket với một địa chỉ IP và số cổng được chỉ định mà tham số SocketAddress đại diện. |
accept() | Lắng nghe để có một kết nối được tạo đến ổ cắm này và chấp nhận nó. Phương thức accept() chặn cho đến khi một client kết nối vào server trên cổng chỉ định hoặc socket hết thời gian chờ. |
getLocalPort() | Trả về số cổng dưới dạng giá trị int mà một đối tượng ServerSocket đang lắng nghe. |
setSoTimeout(int timeout) | Đặt thời gian chờ trong mili giây sau đó một đối tượng ServerSocket dừng việc chấp nhận kết nối từ client. |
isClosed() | Trả về giá trị boolean để chỉ ra liệu một đối tượng ServerSocket có đóng hay không. |
Lớp InetAddress
Lớp InetAddress
đại diện cho một địa chỉ Internet để thực hiện tìm kiếm và tìm kiếm ngược hệ thống Tên Miền (DNS). Một địa chỉ Internet, hoặc địa chỉ IP mà lớp InetAddress
đại diện là một số 32-bit, thường được biểu diễn dưới dạng một bộ tứ 4 số 8-bit, được tách ra bởi các dấu chấm. Ví dụ, 127.0.0.1 là địa chỉ IP của một máy tính cục bộ.
Bảng dưới giải thích về các phương thức quan trọng của lớp InetAddress
.
Phương Thức | Mô Tả |
---|---|
getAddress() | Trả về địa chỉ IP của đối tượng InetAddress dưới dạng mảng byte. |
getByName(String host) | Trả về địa chỉ IP của máy chủ được chuyển vào dưới dạng đối tượng InetAddress . |
getHostName() | Trả về tên máy chủ của đối tượng InetAddress . |
getAllByName(String host) | Trả về một mảng các địa chỉ IP của máy chủ được chuyển vào dưới dạng đối tượng InetAddress . |
isReachable(int timeout) | Trả về giá trị boolean để chỉ ra liệu địa chỉ IP được đại diện bởi InetAddress có thể kết nối được hay không, với thời gian chờ được chỉ định. |
Lớp Inet4Address
Lớp Inet4Address
mở rộng từ lớp InetAddress
và đại diện cho một địa chỉ IPv4. Ngoài ra, nó cung cấp các phương thức để diễn giải và hiển thị thông tin hữu ích về địa chỉ IP.
Dưới đây là bốn định dạng mà các phương thức của lớp Inet4Address
có thể sử dụng:
d.d.d.d
: Mỗi giá trị được gán cho bốn byte của địa chỉ IP từ trái sang phải trong định dạng này.d.d.d
: Phần cuối cùng được diễn giải như một số 16-bit trong định dạng này và địa chỉ máy chủ được gán cho hai byte phải nhất. Do đó, nó được sử dụng để chỉ định một địa chỉ lớp-B.d.d
: Phần cuối cùng được diễn giải như một số 24-bit trong định dạng này và địa chỉ máy chủ được gán cho ba byte phải nhất. Do đó, nó được sử dụng để chỉ định một địa chỉ lớp-A.d
: Trong định dạng này, giá trị được cung cấp được lưu trữ trực tiếp như một địa chỉ mạng mà không cần bất kỳ sắp xếp lại nào.
Bảng dưới giải thích về các phương thức quan trọng của lớp Inet4Address
.
Phương Thức | Mô Tả |
---|---|
equals(Object obj) | So sánh đối tượng hiện tại với đối tượng được chỉ định. |
getAddress() | Trả về địa chỉ IP thô của đối tượng Inet4Address . |
getHostAddress() | Trả về chuỗi địa chỉ IP dưới dạng hiển thị văn bản. |
hashCode() | Trả về một giá trị hash cho địa chỉ IP này. |
isAnyLocalAddress() | Kiểm tra xem Inet4Address có phải là địa chỉ mặc định hay không. |
isLinkLocalAddress() | Kiểm tra xem Inet4Address có phải là địa chỉ link-local hay không. |
isLoopbackAddress() | Kiểm tra xem Inet4Address có phải là địa chỉ loopback hay không. |
isMCGlobal() | Kiểm tra xem địa chỉ đa phương tiện có phạm vi toàn cầu hay không. |
isMCLinkLocal() | Kiểm tra xem địa chỉ đa phương tiện có phạm vi link-local hay không. |
isMCNodeLocal() | Kiểm tra xem địa chỉ đa phương tiện có phạm vi node hay không. |
isMCOrgLocal() | Kiểm tra xem địa chỉ đa phương tiện có phạm vi tổ chức hay không. |
isMCSiteLocal() | Kiểm tra xem địa chỉ đa phương tiện có phạm vi site hay không. |
isMulticastAddress() | Kiểm tra xem địa chỉ Inet4Address có phải là địa chỉ đa phương tiện IP không. |
isSiteLocalAddress() | Kiểm tra xem Inet4Address có phải là địa chỉ site-local hay không. |
Lớp Inet6Address
Lớp Inet6Address
đại diện cho địa chỉ IPV6 và mở rộng từ lớp InetAddress
. Các phương thức của lớp này cung cấp khả năng biểu diễn và diễn giải địa chỉ IPV6.
Dưới đây là các định dạng mà các phương thức của lớp Inet6Address
có thể sử dụng:
- Dạng chung (General Form):
- Là dạng chung của địa chỉ IPV6, trong đó mỗi
x
có thể được thay thế bằng giá trị địa chỉ thập lục phân 16-bit. - Lưu ý: Khi sử dụng định dạng này, mỗi
x
phải có một giá trị. - Ví dụ:
4B0C:0:0:0:880C:99A8:480:4411
- Nén địa chỉ (Compressed Form):
- Được sử dụng khi địa chỉ chứa nhiều bộ 8 bit giống nhau là ‘0.
- Trong trường hợp này,
::
thay thế bằng các số0
để rút gọn địa chỉ. - Ví dụ: Địa chỉ trong ví dụ trước có thể được viết lại thành
480C::880C:99A8:480:4411
- Chế độ kết hợp (Hybrid Mode):
- Sử dụng khi cần xử lý địa chỉ kết hợp (IPv6 + IPv4). 12 byte đầu tiên được sử dụng cho địa chỉ IPv6 và 4 byte còn lại được sử dụng cho IPv4.
- Ví dụ:
F334::40CB:152.16.24.142
- Chế độ ánh xạ IPv4 (IPv4-mapped Mode):
- Được sử dụng để hỗ trợ triển khai địa chỉ IPv6.
- Cho phép sử dụng cùng một cấu trúc và socket để giao tiếp qua mạng kết nối IPv6 và IPv4.
- 80 bit đầu tiên được điền vào bằng số
0
được biểu thị bằngx
. 32 bit tiếp theo là tất cả1
và 32 bit còn lại biểu thị địa chỉ IPv4. - Ví dụ:
:FFFF:152.16.24.123
Bảng dưới giải thích về các phương thức quan trọng của lớp Inet6Address
.
Phương thức | Mô tả |
---|---|
getByAddress(String host, byte[] addr, int scope_id) | Được sử dụng để tạo một đối tượng InetAddress bằng cách đặt một IPv6 scope id với giá trị được chỉ định. |
getByAddress(String host, byte[] addr, Networkinterface nif) | Sử dụng để chỉ định giao diện mạng được sử dụng với địa chỉ. |
getScope_id() | Trả về scope id được liên kết với địa chỉ hoặc 0 nếu không có. |
getScopedinterface() | Trả về giao diện mạng liên kết với địa chỉ hoặc null nếu không có. |
getAddress() | Trả về địa chỉ IP thô của đối tượng InetAddress này dưới dạng mảng. |
getHostAddress() | Trả về địa chỉ IP dưới dạng văn bản. |
isAnyLocalAddress() | Trả về true nếu địa chỉ này đại diện cho địa chỉ cục bộ. |
isLinkLocalAddress() | Trả về true nếu đây là địa chỉ cục bộ kết nối. |
isLoopbackAddress() | Trả về true nếu đây là địa chỉ vòng lặp. |
isMCGlobal() | Trả về true nếu địa chỉ multicast này có phạm vi toàn cầu. |
isMCLinkLocal() | Trả về true nếu địa chỉ multicast này có phạm vi kết nối. |
isMCNodeLocal() | Trả về true nếu địa chỉ multicast này có phạm vi nút. |
isMCOrgLocal() | Trả về true nếu địa chỉ multicast này có phạm vi tổ chức. |
isMCSiteLocal() | Trả về true nếu địa chỉ multicast này có phạm vi trang web. |
isMulticastAddress() | Trả về true nếu đây là một địa chỉ multicast IP. |
isSiteLocalAddress() | Trả về true nếu đây là một địa chỉ cục bộ của trang web. |
hashCode() | Trả về mã băm cho đối tượng địa chỉ này. |
equals(Object obj) | Trả về true nếu địa chỉ IP này giống với đối tượng được chỉ định.Tham số: obj : đối tượng để so sánh. |
Lớp URL
Bảng dưới giải thích về các phương thức quan trọng của lớp URL
.
Phương thức | Mô tả |
---|---|
getPath() | Trả về đường dẫn của URL dưới dạng chuỗi. |
getQuery() | Trả về phần truy vấn của URL dưới dạng chuỗi. |
getPort() | Trả về cổng của URL dưới dạng giá trị int. |
getDefaultPort() | Trả về cổng mặc định cho giao thức của URL dưới dạng giá trị int. |
getProtocol() | Trả về giao thức của URL dưới dạng chuỗi. |
getHost() | Trả về máy chủ của URL dưới dạng chuỗi. |
getFile() | Trả về tên tệp của URL dưới dạng chuỗi. |
openConnection() | Mở một kết nối đến URL và trả về một đối tượng URLConnection . |
Lưu ý: Các phương thức openConnection()
có thể được sử dụng để mở kết nối đến URL và thực hiện các thao tác như đọc, ghi hoặc thậm chí tải xuống nội dung từ URL.
Lớp URLConnection
Lớp URLConnection
được trả về bởi phương thức openConnection()
của lớp URL
, và nó là một lớp trừu tượng đóng vai trò là lớp cơ sở cho các lớp đại diện cho liên kết giao tiếp giữa ứng dụng và một URL.
Bảng dưới giải thích về các phương thức quan trọng của lớp URLConnection
.
Phương thức | Mô tả |
---|---|
getURL() | Trả về URL mà đối tượng URLConnection đang kết nối dưới dạng đối tượng URL . |
setDoInput(boolean input) | Chấp nhận giá trị boolean để chỉ định liệu URLConnection có sử dụng cho đầu vào hay không. Giá trị mặc định là true. |
setDoOutput(boolean output) | Chấp nhận giá trị boolean để chỉ định liệu URLConnection có sử dụng cho đầu ra hay không. Giá trị mặc định là false. |
getInputStream() | Trả về luồng đầu vào của URLConnection dưới dạng đối tượng InputStream . Phương thức này được gọi để đọc từ một URL. |
getOutputStream() | Trả về luồng đầu ra của URLConnection dưới dạng đối tượng OutputStream . Phương thức này được gọi để ghi vào một URL. |
getContent() | Trả về đối tượng chứa nội dung của URLConnection . |
getContentEncoding() | Trả về trường tiêu đề content-encoding của URLConnection dưới dạng chuỗi. |
getContentLength() | Trả về trường tiêu đề content-length của URLConnection dưới dạng giá trị int. |
getContentType() | Trả về trường tiêu đề content-type của URLConnection dưới dạng chuỗi. |
getHeaderField(String) | Trả về giá trị của trường tiêu đề được chỉ định của URLConnection dưới dạng chuỗi. |
getDate() | Trả về trường tiêu đề ngày của URLConnection dưới dạng giá trị long. |
getExpiration() | Trả về trường tiêu đề hết hạn của URLConnection dưới dạng giá trị long. |
getLastModified() | Trả về trường tiêu đề lần sửa đổi cuối cùng của URLConnection dưới dạng giá trị long. |
getHeaderFields() | Trả về tất cả các trường tiêu đề của URLConnection dưới dạng Map<String, List<String>> . |
getIfModifiedSince() | Trả về giá trị của trường tiêu đề ifModifiedSince dưới dạng giá trị long. |
Lưu ý: URLConnection
là một lớp trừu tượng và các đối tượng thực thi của nó thường được trả về bởi phương thức openConnection()
của lớp URL
.
Lớp URLPermission
Lớp URLPermission
được sử dụng để đại diện cho quyền truy cập vào các nguồn tài nguyên của URL cụ thể. Các hành động (actions) đại diện cho các phương thức yêu cầu và tiêu đề (headers). URL được chọn làm tên quyền.
Ví dụ:
"POST, GET:Header1, Header2"
Trong ví dụ này, có hai phương thức yêu cầu và hai tiêu đề, được phân tách bằng dấu hai chấm. Nếu danh sách phương thức yêu cầu và tiêu đề rỗng, thì dấu hai chấm không cần thiết. Trong chuỗi hành động, không có quyền cho khoảng trắng.
Khai báo lớp
public final class URLPermission extends Permission
Một phiên bản mới của lớp URLPermission
với URL cụ thể có thể được tạo bằng cách sử dụng constructor URLPermission(String url)
. Một phiên bản mới của lớp URLPermission
với URL và hành động cụ thể có thể được tạo bằng cách sử dụng constructor URLPermission(String url, String actions)
.
Phương thức
Bảng dưới giải thích về các phương thức quan trọng của lớp URLPermission
.
Phương thức | Mô tả |
---|---|
equals(Object p) | Kiểm tra xem hai đối tượng URLPermission có bằng nhau hay không. |
getActions() | Trả về các hành động dưới dạng chuỗi, hiện tại là danh sách các phương thức đã được chuẩn hóa và gửi yêu cầu cho danh sách tiêu đề. |
hashCode() | Trả về giá trị băm của đối tượng này. |
implies(Permission p) | Kiểm tra xem đối tượng có ngụ ý quyền cụ thể đã cho hay không. |
Lớp HttpURLPermission
Lớp HttpURLPermission
là một lớp đại diện cho quyền truy cập vào một tập hợp các nguồn tài nguyên hoặc một nguồn tài nguyên được chỉ định bởi một URL thuộc giao thức https hoặc http. Một tập hợp các phương thức yêu cầu và tiêu đề yêu cầu, có thể được thiết lập bởi người dùng, cũng được đại diện bởi HttpURLPermission
qua tên của nó. Các phương thức yêu cầu và tiêu đề được biểu diễn dưới dạng chuỗi hành động. Phạm vi của tên phương thức và tiêu đề không có giới hạn trong lớp này.
Cú pháp
public class HttpURLPermission extends java.security.Permission
Cách xác định đường dẫn trong URL
- Đường dẫn của URL được chỉ định tương tự như đường dẫn trong
FilePermission
. - Dưới đây là ba cách khác nhau với các URL ví dụ:
http://www.oracle.com/a/b/c.html
- URL này xác định một nguồn tài nguyên cụ thể (duy nhất).
http://www.oracle.com/a/b/*
- Ký tự
*
đề cập đến tất cả các nguồn tài nguyên trong cùng “thư mục” – nghĩa là tất cả các nguồn tài nguyên có cùng số thành phần đường dẫn và chỉ khác nhau ở thành phần đường dẫn cuối cùng, được biểu diễn bởi “*”.
http://www.oracle.com/a/b/-
- Ký tự
-
tham chiếu đến tất cả các nguồn tài nguyên đệ quy dưới đường dẫn trước đó (ví dụ: http://www.oracle.com/a/b/c/d/e.html sẽ khớp với ví dụ này).
Lập Trình Socket và Xử Lý URL
Các lớp socket và ServerSocket trong gói java.net cho phép lập trình socket qua TCP, Lập trình socket liên quan đến một máy chủ và một máy khách.
Chương Trình Máy Chủ/Máy Khách
Tạo máy chủ ServerSocket
Trong các chương trình máy chủ/máy khách giao tiếp sử dụng TCP/IP, một máy chủ được tạo để lắng nghe các kết nối từ máy khách. Sau đó, một máy khách được tạo để kết nối với máy chủ và trao đổi gói dữ liệu.
Các bước để tạo một lớp máy chủ như sau:
- Tạo đối tượng server socket như một Serversocket.
- Chờ yêu cầu từ máy khách.
- Tạo luồng đầu vào và đầu ra để nhận và gửi dữ liệu tương ứng.
- Thực hiện giao tiếp với máy khách.
- Đóng socket.
Đoạn mã dưới thể hiện việc sử dụng ServerSocket để tạo một máy chủ.
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
public class Server extends Thread {
private ServerSocket serverSocket;
public Server(int port) throws IOException {
serverSocket = new ServerSocket(port);
}
public void run() {
while (true) {
try {
System.out.println("Listening for client message on port " + serverSocket.getLocalPort());
Socket socket = serverSocket.accept();
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
out.writeUTF("Hello from server.");
} catch (SocketTimeoutException stException) {
stException.printStackTrace();
} catch (IOException ioException) {
ioException.printStackTrace();
} finally {
try {
serverSocket.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
}
public static void main(String[] args) {
try {
Thread thread = new Server(6060);
thread.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Mã này tạo một lớp Server
mở rộng từ Thread
. Constructor tạo một đối tượng ServerSocket
với cổng được chỉ định được truyền làm tham số. Trong phương thức run()
được ghi đè của lớp Thread
, mã gọi phương thức accept()
của serverSocket
để nhận một đối tượng Socket
. Mã sau đó xây dựng một đối tượng DataOutputStream
và sử dụng nó để ghi một thông điệp. Phương thức main()
tạo một đối tượng Server
như một Thread
và bắt đầu.
Bước tiếp theo, chúng ta tiến hành tạo lớp Client.
Tạo Một Client
Các bước để tạo một lớp máy khách như sau:
- Tạo một socket như một đối tượng Socket.
- Tạo luồng đầu vào và đầu ra để nhận và gửi dữ liệu tương ứng.
- Thực hiện giao tiếp với máy chủ.
- Đóng socket.
Đoạn mã dưới thể hiện cách sử dụng lớp Socket để tạo một máy khách
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args) {
try (Socket clientSocket = new Socket("localhost", 6060);
InputStream fromServer = clientSocket.getInputStream();
DataInputStream in = new DataInputStream(fromServer)) {
System.out.println("Message received from server: " + in.readUTF());
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Tiếp theo, click chuột phải vào Properties dự án của netbean, đặt Server Class run as main như hình mô tả:
Output:
Bước tiếp theo, làm tương tự với Client:
Xử lý URL
URL là địa chỉ của một tài nguyên trên Internet. Java cung cấp các lớp URL và URLConnection để viết các chương trình Java giao tiếp với một URL. Bằng cách sử dụng cả hai lớp URL và URLConnection, bạn có thể tạo một URL cho một trang web, thiết lập kết nối đến trang web và truy xuất nội dung của trang web.
Ví dụ:
import java.io.*;
import java.net.*;
public class URLProcessingDemo {
public static void main(String[] args) {
try {
URL url = new URL("http://www.google.com");
URLConnection urlConnection = url.openConnection();
InputStream stream = urlConnection.getInputStream();
int i;
while ((i = stream.read()) != -1) {
System.out.print((char) i);
}
stream.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
Trong phương thức main(), đoạn mã tạo một đối tượng URL cho http://www.google.com. Phương thức getConnection() trả về một đối tượng URLConnection được chuyển đổi thành đối tượng HttpURLConnection. Phương thức getInputStream() của URLConnection trả về một InputStream được sử dụng để tạo một đối tượng InputStreamReader. Sau đó, đoạn mã tạo một đối tượng BufferedReader của InputStreamReader và sử dụng phương thức readline() trong một vòng lặp while để lấy từng dòng nội dung từ URL http://www.google.com. Cuối cùng, nội dung được lấy được in ra màn hình.
Output:
Bài tập
Bài 1:
Câu 1: Ứng dụng quản lý sách trong thư viện
Phát triển một ứng dụng console để quản lý sách trong thư viện với các chức năng sau:
- Thêm thông tin sách vào danh sách.
- Lưu danh sách sách vào một tệp.
- Đọc dữ liệu từ tệp và hiển thị thông tin sách trong console.
- Tìm kiếm sách dựa trên tên sách (
bookTitle
) hoặc tác giả (author
).
Dữ liệu cần lưu trữ:
- Id: Chuỗi
- Tên sách (bookTitle): Chuỗi, chứa ít nhất 5 ký tự.
- Tác giả (author): Chuỗi.
- Năm xuất bản (publishedYear): Kiểu số nguyên, lớn hơn 1900.
- Thể loại (genre): Danh sách các thể loại sách (ví dụ: tiểu thuyết, khoa học, văn học...).
Yêu cầu:
- Tạo một lớp Kiểm tra (Test class) để:
- Khai báo danh sách 5 sách với thông tin nhập từ bàn phím (sử dụng gói
java.io
thay vìScanner
). - Xác minh điều kiện đầu vào cho các trường
bookTitle
vàpublishedYear
. - Sau khi nhập đủ dữ liệu, lưu vào tệp
library_data.txt
. - Đọc dữ liệu từ
library_data.txt
và hiển thị trên console. - Cho phép tìm kiếm sách theo tên hoặc tác giả; nếu không tìm thấy, hiển thị "KHÔNG TÌM THẤY".
- Khai báo danh sách 5 sách với thông tin nhập từ bàn phím (sử dụng gói
Câu 2: Luồng xử lý (Thread) - Quản lý số lượng sách theo thể loại
-
Xây dựng một
Map<String, Integer>
để lưu trữ số lượng sách theo từng thể loại, ví dụ:- Tiểu thuyết: 10
- Khoa học: 7
- Văn học: 12
-
Luồng thứ nhất: Cứ mỗi giây, chọn ngẫu nhiên một thể loại sách và tăng số lượng của thể loại đó lên 1, sau đó hiển thị thể loại vừa được chọn cùng số lượng cập nhật.
-
Luồng thứ hai: Theo dõi tổng số lượng sách đã được thêm vào mỗi giây và hiển thị tổng số lượng sách trong thư viện.
Viết phương thức main()
để thực hiện hai luồng này, đảm bảo hai luồng hoạt động đồng bộ và hiển thị dữ liệu chính xác.
Bài 2:
Câu 1: Ứng dụng quản lý kho sản phẩm
Phát triển một ứng dụng console để quản lý kho hàng với các yêu cầu:
- Thêm thông tin sản phẩm vào danh sách.
- Lưu danh sách sản phẩm vào tệp.
- Đọc dữ liệu từ tệp và hiển thị thông tin sản phẩm trong console.
- Tìm kiếm sản phẩm theo tên sản phẩm (
productName
) hoặc danh mục (category
).
Thông tin cần lưu trữ:
- Mã sản phẩm (productId): Chuỗi.
- Tên sản phẩm (productName): Chuỗi, chứa ít nhất 3 ký tự.
- Giá bán (price): Kiểu số thực, lớn hơn 0.
- Số lượng (quantity): Kiểu số nguyên.
- Danh mục (category): Danh sách các danh mục sản phẩm (ví dụ: điện tử, gia dụng, thời trang...).
Yêu cầu:
- Tạo một lớp kiểm tra để:
- Khởi tạo danh sách 5 sản phẩm với dữ liệu nhập từ bàn phím (sử dụng
java.io
). - Kiểm tra tính hợp lệ của
productName
vàprice
. - Lưu dữ liệu sản phẩm vào tệp
inventory_data.txt
. - Đọc và hiển thị dữ liệu từ
inventory_data.txt
trên console. - Cho phép tìm kiếm sản phẩm theo tên hoặc danh mục; nếu không có kết quả phù hợp, hiển thị "KHÔNG TÌM THẤY".
- Khởi tạo danh sách 5 sản phẩm với dữ liệu nhập từ bàn phím (sử dụng
Câu 2: Luồng xử lý (Thread) - Quản lý số lượng nhập xuất sản phẩm
-
Tạo một
Map<String, Integer>
để lưu trữ số lượng sản phẩm nhập và xuất hàng giờ. Ví dụ:- Điện thoại: 20 nhập, 5 xuất
- Tivi: 15 nhập, 3 xuất
-
Luồng thứ nhất: Mỗi giây, chọn một sản phẩm ngẫu nhiên và cập nhật số lượng nhập thêm (tăng lên 1 đơn vị), sau đó hiển thị sản phẩm vừa nhập và số lượng mới.
-
Luồng thứ hai: Đồng bộ với luồng thứ nhất, chọn ngẫu nhiên một sản phẩm khác để cập nhật số lượng xuất (giảm đi 1 đơn vị) và hiển thị số lượng sau khi xuất.
Viết phương thức main()
để thực hiện hai luồng này, đảm bảo dữ liệu cập nhật chính xác và đồng bộ.
Bài 3:
Question 1:
Tạo một lớp bean tên là **Book** để mô tả thông tin sách với các thuộc tính:
- `private String ISBN;`
- `private String title;`
- `private String author;`
- `private double price;`
Yêu cầu:
1. Lớp này phải có:
- Hai constructors:
- Constructor mặc định.
- Constructor với tham số để gán giá trị cho các thuộc tính.
- Các phương thức getter và setter.
- Override phương thức `toString()` của lớp Object để trả về thông tin của sách.
2. Tạo một lớp tên là **BookTest** để kiểm tra:
- Nhập 5 quyển sách từ bàn phím và lưu chúng vào danh sách kiểu `List<Book>` (sử dụng generic).
- Validate ISBN theo định dạng: 3 chữ số - 2 ký tự chữ - 4 chữ số (VD: 123-AB-4567 là hợp lệ, 12-ABC-456 là không hợp lệ). Nếu không hợp lệ, yêu cầu người dùng nhập lại.
3. Ghi danh sách sách vào tệp tin **books.dat**.
4. Đọc tệp **books.dat** để lấy danh sách sách, sau đó hiển thị chúng trên màn hình console.
5. Từ danh sách sách đã đọc, hiển thị thông tin tất cả sách có giá dưới 50.
---
Question 2:
1. Tạo lớp **Data** để lưu trữ mảng chuỗi sau:
String[] data = {"Hello", "Java", "Programming"};
2. Tạo lớp tên là ThreadProcessor.java để:
- Lấy từng chuỗi từ mảng của lớp Data và đảo ngược chuỗi đó.
- Gửi giá trị đã đảo ngược sang lớp ThreadPrinter để hiển thị.
3. Tạo lớp tên là ThreadPrinter.java để:
- Hiển thị các chuỗi đã đảo ngược từ lớp **ThreadProcessor**.
4. Tạo lớp tên là Test để kiểm tra hai lớp trên.
Lưu ý:
- Sử dụng các cơ chế synchronized, wait, và notify để xử lý dữ liệu giữa các luồng.