利用 XML - RPC 创建 Web 服务及 Java 正则表达式应用
1. XML - RPC 简介
XML - RPC 被描述为远程过程调用协议的“最低公分母”,但它的创造者并不认为这是一种贬低。大多数促进网络软件通信的尝试都非常复杂,这让一些有简单需求的开发者望而却步。而 XML - RPC 协议可以与任何支持 HTTP(网络通用语言)和 XML(高度流行、人类可读的数据格式)的软件交换信息。通过查看 XML - RPC 请求和响应,即使不阅读协议规范,也能弄清楚如何使用该协议。随着 Apache XML - RPC 等实现的不断扩展,甚至无需查看协议就能快速使用它。
2. 使用 XML - RPC 创建 Web 服务
2.1 SiteClient 应用
SiteClient 应用程序会连接到 XML - RPC 服务器,并调用服务器上的
dmoz.getRandomSite()
方法,该方法无参数。此方法返回一个
Vector
,其中包含四个字符串:“ok”(表示请求已完成)以及网站的 URL、标题和描述。以下是相关代码:
// Create the client
XmlRpcClient client = new XmlRpcClient(
"http://cadenhead.org:4413/");
// Create the parameters for the request
Vector params = new Vector();
// Send the request and get the response
Vector result = (Vector) client.execute("dmoz.getRandomSite", params);
return result;
2.2 XML - RPC 服务器
XML - RPC 服务器是一个接收客户端请求、调用相应方法并返回结果的程序。服务器维护一个允许客户端调用的方法列表,这些方法位于不同的 Java 类中,称为处理程序(handlers)。使用
org.apache.xmlrpc
包中的类可以远程提供方法,最简单的方法是使用
WebServer
类,它代表一个仅响应 XML - RPC 请求的简单 HTTP Web 服务器。
WebServer
类有两个构造函数:
-
WebServer(int)
:创建一个监听指定端口号的 Web 服务器。
-
WebServer(int, InetAddress)
:在指定端口和 IP 地址创建一个 Web 服务器,第二个参数是
java.net.InetAddress
类的对象。
两个构造函数在创建和启动服务器时如果出现输入/输出问题,都会抛出
IOException
异常。以下代码创建一个在端口 4413 上的 XML - RPC Web 服务器:
int port = Integer.parseInt("4413");
WebServer server = new WebServer(port);
Web 服务器本身不包含客户端通过 XML - RPC 调用的远程方法,这些方法位于其他 Java 类(处理程序)中。要添加处理程序,可调用服务器的
addHandler(String, Object)
方法,指定处理程序名称和处理程序对象。例如:
DmozHandler odp = new DmozHandler();
server.addHandler( "dmoz", odp);
2.3 DmozServer 应用
以下是
DmozServer.java
的完整代码:
import java.io.IOException;
import org.apache.xmlrpc.WebServer;
import org.apache.xmlrpc.XmlRpc;
public class DmozServer {
public static void main(String[] arguments) {
if (arguments.length < 1) {
System.out.println("Usage: java DmozServer [port]");
System.exit(0);
}
try {
startServer(arguments[0]);
} catch (IOException ioe) {
System.out.println("Server error: " +
ioe.getMessage());
}
}
public static void startServer(String portString) throws IOException {
// Start the server
int port = Integer.parseInt(portString);
System.out.println("Starting Dmoz server ...");
WebServer server = new WebServer(port);
// Register the handler
DmozHandler odp = new DmozHandler();
server.addHandler( "dmoz", odp);
System.out.println("Accepting requests ...");
}
}
2.4 DmozHandler 类
DmozHandler
类用于处理远程方法调用,以下是其完整代码:
import java.sql.*;
import java.util.*;
public class DmozHandler {
public Vector getRandomSite() {
Connection conn = getMySqlConnection();
Vector response = new Vector();
try {
Statement st = conn.createStatement();
ResultSet rec = st.executeQuery(
"SELECT * FROM cooldata ORDER BY RAND() LIMIT 1");
if (rec.next()) {
response.addElement("ok");
response.addElement(rec.getString("url"));
response.addElement(rec.getString("title"));
response.addElement(rec.getString("description"));
} else {
response.addElement("database error: no records found");
}
} catch (SQLException sqe) {
response.addElement("database error: " + sqe.getMessage());
}
return response;
}
private Connection getMySqlConnection() {
Connection conn = null;
String data =
"jdbc:mysql://localhost/cadenhead?user=stu&password=sm50";
try {
Class.forName("org.gjt.mm.mysql.Driver");
conn = DriverManager.getConnection(
data, "", "");
} catch (SQLException s) {
System.out.println("SQL Error: " + s.toString() + " "
+ s.getErrorCode() + " " + s.getSQLState());
} catch (Exception e) {
System.out.println("Error: " + e.toString()
+ e.getMessage());
}
return conn;
}
}
2.5 运行和修改
运行服务器时,需在命令行指定端口号,例如:
java DmozServer 4413
服务器启动后,可修改
SiteClient
应用程序以连接到自己的 XML - RPC 服务器,将相关代码修改为:
XmlRpcClient client = new XmlRpcClient(
"http://localhost:4413/");
2.6 常见问题解答
| 问题 | 答案 |
|---|---|
| 如果 XML - RPC 代表最终导致 SOAP 发布的规范的“快照”,为什么 XML - RPC 仍然可用? | XML - RPC 规范在 1998 年由 UserLand Software 发布后,被不同的开发者迅速实现,为该协议创造了相当大的发展动力。当 SOAP 出现且比 XML - RPC 复杂得多时,这两个相关协议之间存在足够的差异,可根据特定项目的需求选择使用其中之一。 |
当尝试从远程方法返回
HashMap
对象时,Apache XML - RPC 会响应一个
XmlRpcException
,指出该对象不受支持。它支持哪些对象?
|
Apache XML - RPC 返回以下数据类型:
Boolean
(对应 boolean XML - RPC 值)、
byte[]
(对应 base64 数据)、
Date
(对应
dateTime.iso8601
数据)、
Double
(对应 double 值)、
Integer
(对应 int 或 i4 值)、
String
(对应字符串)、
Hashtable
(对应 struct 值)或
Vector
(对应数组)。
|
编写一个 XML - RPC 客户端来调用一个返回二进制数据(即 base64)的方法,
XmlRpcClient
的
execute()
方法返回一个对象而不是字节数组,如何进行转换?
|
在 Java 中数组也是对象,因此可以使用强制类型转换将
execute()
返回的对象转换为字节数组(假设该对象确实是一个数组)。例如:
byte[] data = (byte[]) fromServer;
|
2.7 流程图
graph TD
A[客户端] -->|发送请求| B[XML - RPC 服务器]
B -->|调用处理程序方法| C[处理程序(如 DmozHandler)]
C -->|执行方法| D[数据库(如 MySQL)]
D -->|返回数据| C
C -->|返回结果| B
B -->|返回响应| A
3. Java 正则表达式简介
在 Java 2 版本 1.4 发布之前,使用 Sun 的 Java 类库进行文本处理是一项较为困难的任务。因为它缺乏对正则表达式(一种复杂的文本处理形式)的支持,使得原本可以用一行 Perl 代码完成的搜索和替换操作在 Java 中变得艰巨。新版本的 Java 引入了
java.util.regex
包,并对几个包含字符的类进行了更改,从而为正则表达式提供了强大的支持。
4. 正则表达式基础
4.1 模式匹配介绍
正则表达式(也称为 regex)是处理文本最流行的方式,它是一种表达可能出现在一行或大段文本中的模式的标准方法。正则表达式在多种计算机编程语言中都有实现,与 Perl 脚本语言的关联最为紧密。大多数流行语言将其作为语言的核心部分或可选模块/库提供,使具有正则表达式技能的程序员能够在多种语言中应用这些技能。这类似于结构化查询语言(SQL),它已被众多语言和数据库供应商实现,可在 Java、Visual C++ 等许多开发环境中使用。
正则表达式是一系列字符和标点符号,用于描述可能在文本中找到的模式。可以使用此模式查找所需内容、提取部分文本、用新内容替换文本等。
4.2 Java 对正则表达式的支持
Sun 对正则表达式的支持体现在三个方面:
-
javax.util.regex
包:仅由两个类(
Pattern
和
Matcher
)和一个异常(
PatternSyntaxException
)组成。
- 表示字符序列的三个 Java 类:
java.lang
包中的
String
和
StringBuffer
以及
java.nio
包中的
CharBuffer
。
-
java.lang
中的
CharSequence
接口:这是一个新接口,由
String
、
StringBuffer
和
CharBuffer
共享。
4.3 CharSequence 接口
CharSequence
接口是 Java 2 版本 1.4 为支持正则表达式引入的,它包含四个方法:
-
length()
:返回序列中的字符数。
-
charAt(int)
:返回序列中指定位置的字符。
-
subSequence(int, int)
:返回包含序列一部分的
CharSequence
。
-
toString()
:返回包含该序列的
String
。
此接口由
String
、
StringBuffer
和
CharBuffer
三个类实现。
4.4 使用正则表达式
java.util.regex
中的正则表达式只需要
Pattern
和
Matcher
两个类的交互。
4.4.1 查找匹配项
要将整个字符序列与模式进行比较,可调用
Pattern
类的
matches(String, CharSequence)
方法。例如:
boolean pm = Pattern.matches("[Aa]mazon.com", store);
String
类也有一个
matches(String)
方法,用于判断调用该方法的字符串是否包含指定模式。这两个
matches()
方法在仅测试一次模式且要在整个字符序列中查找时适用,它们使用 Java 中模式匹配的默认行为。
4.4.2 TestPatterns 应用
以下是
TestPatterns.java
的完整代码:
import java.awt.*;
import java.awt.event.*;
import java.util.regex.*;
import javax.swing.*;
public class TestPatterns extends JFrame implements ActionListener {
JTextArea text = new JTextArea(5, 29);
JTextField pattern = new JTextField(35);
JButton search = new JButton("Search");
JButton newSearch = new JButton("New Search");
JTextArea result = new JTextArea(5, 29);
public TestPatterns() {
super("Test Patterns");
setSize(430, 320);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container pane = getContentPane();
GridLayout grid = new GridLayout(3, 1);
pane.setLayout(grid);
// set up the top row
JLabel textLabel = new JLabel("Text: ");
JPanel row1 = new JPanel();
row1.add(textLabel);
JScrollPane scroll = new JScrollPane(text,
ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
row1.add(scroll);
// set up the middle row
JPanel row2 = new JPanel();
JLabel patternLabel = new JLabel("Pattern: ");
row2.add(patternLabel);
row2.add(pattern);
search.addActionListener(this);
newSearch.addActionListener(this);
row2.add(search);
row2.add(newSearch);
// set up the bottom row
JPanel row3 = new JPanel();
JLabel resultLabel = new JLabel("Result: ");
row3.add(resultLabel);
result.setEditable(false);
JScrollPane scroll2 = new JScrollPane(result,
ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
row3.add(scroll2);
// set up the content pane
pane.add(row1);
pane.add(row2);
pane.add(row3);
setContentPane(pane);
setVisible(true);
}
public void actionPerformed(ActionEvent evt) {
Object source = evt.getSource();
if (source == search) {
checkPattern();
} else {
pattern.setText("");
result.setText("");
}
}
private void checkPattern() {
try {
if (Pattern.matches(pattern.getText(), text.getText()))
result.setText("That pattern was found");
else
result.setText("That pattern was not found");
} catch (PatternSyntaxException pse) {
result.setText("Regex error: " + pse.getMessage());
}
}
public static void main(String[] arguments) {
TestPatterns app = new TestPatterns();
}
}
该应用程序可用于测试 Java 对正则表达式的支持。在“Text”区域输入字符串,在“Pattern”字段输入正则表达式,点击“Search”按钮查看模式是否在文本中找到,点击“New Search”按钮可尝试不同的模式。
4.5 用模式分割字符串
Java 2 版本 1.4 引入了更通用的字符串分割技术,
String
类中的两个
split()
方法使用正则表达式作为分隔符,而不是单个字符:
-
split(String)
:返回一个
String[]
数组,包含由指定模式分隔的子字符串。
-
split(String, int)
:返回一个
String[]
数组,包含由指定模式分隔的子字符串,数组元素有最大数量限制(第二个参数)。
以下是
SplitData.java
的代码:
import java.util.regex.*;
public class SplitData {
String[] input = { "320/10.50/Dec 11 2002/39.95",
"110-4.25-Dec 15 2002-39.95",
"8%54.00%Dec 4 2002%0" };
}
该程序展示了
split()
方法的使用,它查看三行使用不同分隔符(
/
、
-
和
%
)的股票价格数据。
4.6 常见问题及解答
| 问题 | 答案 |
|---|---|
| XML - RPC 不需要以下哪种流行的 Internet 协议? | HTML。XML - RPC 使用 HTTP(超文本传输协议)来传输格式为 XML(可扩展标记语言)的数据,不使用 HTML(超文本标记语言)。 |
| 哪种 XML - RPC 数据类型最适合保存数字 8.67? | double。在 XML - RPC 中,所有浮点数(如 8.67)都由 double 类型表示,不像 Java 中有 float 和 double 两种不同的浮点类型。 |
| 哪个 XML 标签表示数据是 XML - RPC 请求? |
methodCall。
methodCall
标签仅用于请求,
methodResponse
仅用于响应,
params
用于两者。
|
4.7 流程图
graph TD
A[输入文本和模式] --> B[调用 Pattern.matches 方法]
B -->|模式有效| C{模式是否匹配}
C -->|是| D[显示“模式已找到”]
C -->|否| E[显示“模式未找到”]
B -->|模式无效| F[捕获 PatternSyntaxException]
F --> G[显示错误信息]
5. 正则表达式语法示例
正则表达式的语法复杂且精妙,学习起来颇具挑战性。下面通过一些具体示例来深入理解其用法。
5.1 字符类
字符类用于匹配一组字符中的任意一个。例如:
-
[abc]
:匹配字符
a
、
b
或
c
。
-
[^abc]
:匹配除
a
、
b
和
c
之外的任意字符。
-
[a - z]
:匹配小写字母
a
到
z
之间的任意字符。
-
[A - Z]
:匹配大写字母
A
到
Z
之间的任意字符。
-
[0 - 9]
:匹配数字
0
到
9
之间的任意字符。
示例代码:
import java.util.regex.Pattern;
public class CharacterClassExample {
public static void main(String[] args) {
String text = "abc123";
boolean isMatch = Pattern.matches("[a - z]+[0 - 9]+", text);
System.out.println("是否匹配: " + isMatch);
}
}
5.2 预定义字符类
Java 提供了一些预定义的字符类,方便我们使用。
| 预定义字符类 | 描述 |
| ---- | ---- |
|
.
| 匹配任意单个字符(除了换行符) |
|
\d
| 匹配数字,等价于
[0 - 9]
|
|
\D
| 匹配非数字,等价于
[^0 - 9]
|
|
\s
| 匹配空白字符,包括空格、制表符、换行符等 |
|
\S
| 匹配非空白字符 |
|
\w
| 匹配单词字符,包括字母、数字和下划线,等价于
[a - zA - Z0 - 9_]
|
|
\W
| 匹配非单词字符 |
示例代码:
import java.util.regex.Pattern;
public class PredefinedCharacterClassExample {
public static void main(String[] args) {
String text = "abc123";
boolean isMatch = Pattern.matches("\\w+", text);
System.out.println("是否匹配: " + isMatch);
}
}
5.3 量词
量词用于指定模式出现的次数。
| 量词 | 描述 |
| ---- | ---- |
|
*
| 匹配前面的元素零次或多次 |
|
+
| 匹配前面的元素一次或多次 |
|
?
| 匹配前面的元素零次或一次 |
|
{n}
| 匹配前面的元素恰好
n
次 |
|
{n,}
| 匹配前面的元素至少
n
次 |
|
{n,m}
| 匹配前面的元素至少
n
次,但不超过
m
次 |
示例代码:
import java.util.regex.Pattern;
public class QuantifierExample {
public static void main(String[] args) {
String text = "aaaa";
boolean isMatch = Pattern.matches("a{2,4}", text);
System.out.println("是否匹配: " + isMatch);
}
}
5.4 分组和捕获
分组是将多个字符组合成一个单元,方便进行量词操作或捕获匹配的内容。使用圆括号
()
进行分组。
示例代码:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GroupingExample {
public static void main(String[] args) {
String text = "abcabc";
Pattern pattern = Pattern.compile("(abc)+");
Matcher matcher = pattern.matcher(text);
if (matcher.find()) {
System.out.println("匹配到的内容: " + matcher.group());
}
}
}
5.5 流程图
graph TD
A[输入文本和正则表达式] --> B[编译正则表达式为 Pattern 对象]
B --> C[创建 Matcher 对象]
C --> D{是否找到匹配项}
D -->|是| E[处理匹配结果]
D -->|否| F[结束处理]
6. 正则表达式的高级应用
6.1 替换文本
使用
Matcher
类的
replaceAll()
和
replaceFirst()
方法可以替换匹配的文本。
示例代码:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ReplaceExample {
public static void main(String[] args) {
String text = "Hello, World!";
Pattern pattern = Pattern.compile("World");
Matcher matcher = pattern.matcher(text);
String newText = matcher.replaceAll("Java");
System.out.println("替换后的文本: " + newText);
}
}
6.2 查找所有匹配项
使用
Matcher
类的
find()
方法可以查找所有匹配项。
示例代码:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class FindAllExample {
public static void main(String[] args) {
String text = "abc123abc456";
Pattern pattern = Pattern.compile("abc");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println("找到匹配项: " + matcher.group() + ",起始位置: " + matcher.start());
}
}
}
6.3 自定义匹配器
可以通过继承
Matcher
类或实现相关接口来自定义匹配器的行为。
6.4 性能优化
在处理大量文本时,正则表达式的性能可能成为瓶颈。可以通过以下方法进行优化:
- 编译正则表达式:将正则表达式编译为
Pattern
对象,避免重复编译。
- 减少回溯:避免使用复杂的量词和嵌套分组,减少回溯的可能性。
- 缓存结果:对于频繁使用的正则表达式和文本,可以缓存匹配结果。
6.5 流程图
graph TD
A[输入文本和替换规则] --> B[编译正则表达式为 Pattern 对象]
B --> C[创建 Matcher 对象]
C --> D{是否找到匹配项}
D -->|是| E[替换匹配项]
E --> F{是否还有匹配项}
F -->|是| D
F -->|否| G[输出替换后的文本]
D -->|否| G
7. 总结
本文详细介绍了利用 XML - RPC 创建 Web 服务以及 Java 正则表达式的相关知识。
7.1 XML - RPC 总结
- XML - RPC 是一种简单的远程过程调用协议,使用 HTTP 和 XML 进行数据传输。
-
通过
WebServer类可以创建 XML - RPC 服务器,通过XmlRpcClient类可以创建客户端。 -
处理程序(如
DmozHandler)包含客户端可以调用的远程方法。
7.2 正则表达式总结
-
Java 2 版本 1.4 引入了对正则表达式的支持,通过
java.util.regex包实现。 -
正则表达式由
Pattern和Matcher两个类主要负责处理。 - 正则表达式的语法丰富多样,包括字符类、预定义字符类、量词、分组等。
- 可以使用正则表达式进行文本匹配、分割、替换等操作。
通过掌握 XML - RPC 和正则表达式的知识,开发者可以更高效地进行网络通信和文本处理,为开发复杂的应用程序打下坚实的基础。
7.3 表格总结
| 技术 | 主要类 | 主要方法 | 应用场景 |
|---|---|---|---|
| XML - RPC |
WebServer
、
XmlRpcClient
、
DmozHandler
|
addHandler()
、
execute()
、
getRandomSite()
| 远程方法调用、Web 服务创建 |
| 正则表达式 |
Pattern
、
Matcher
|
matches()
、
split()
、
replaceAll()
、
find()
| 文本匹配、分割、替换、查找 |
超级会员免费看
3741

被折叠的 条评论
为什么被折叠?



