Java 小程序与 Servlet 前端交互及 JDBC 数据库操作
在 Java 开发中,小程序(Applet)与 Servlet 的交互以及 JDBC 数据库操作是非常重要的部分。下面我们将详细探讨这些内容。
1. 小程序作为 Servlet 前端的应用
1.1 查询集合与生成器
在 Java 开发中,我们可以使用小程序作为 Servlet 的前端。例如,
QueryCollection.java
中的
retrieveQueries
方法用于从指定的 URL 连接中获取查询字符串数组。以下是该方法的代码:
private String[] retrieveQueries() throws IOException {
URLConnection connection = dataURL.openConnection();
connection.setUseCaches(false);
ObjectInputStream in = new ObjectInputStream(connection.getInputStream());
try {
String[] queryStrings = (String[])in.readObject();
return(queryStrings);
} catch(ClassNotFoundException cnfe) {
return(null);
}
}
而
QueryGenerator.java
则是一个 Servlet,用于生成字符串数组并通过
ObjectOutputStream
发送给小程序或其他 Java 客户端。以下是其核心代码:
public class QueryGenerator extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
boolean useNumbering = true;
String useNumberingFlag = request.getParameter("useNumbering");
if ((useNumberingFlag == null) || useNumberingFlag.equals("false")) {
useNumbering = false;
}
String contentType = "application/x-java-serialized-object";
response.setContentType(contentType);
ObjectOutputStream out = new ObjectOutputStream(response.getOutputStream());
String[] queries = getQueries(useNumbering);
out.writeObject(queries);
out.flush();
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
private String[] getQueries(boolean useNumbering) {
String[] queries = new String[50];
for(int i=0; i<queries.length; i++) {
queries[i] = randomQuery();
if (useNumbering) {
queries[i] = "" + (i+1) + ": " + queries[i];
}
}
return(queries);
}
private String randomQuery() {
String[] locations = { "Where ", "How " };
String[] actions = { "can I look for ", "can I find ", "can I get " };
String[] sources = { "information ", "resources ", "data ", "references " };
String[] prepositions = { "on ", "about ", "concerning " };
String[] subjects = { "the book Core Servlets and JavaServer Pages",
"the text Core Servlets and JavaServer Pages",
"Core Servlets and JavaServer Pages",
"Core Servlets and JSP",
"the book Core Web Programming (Java 2 Edition)",
"Core Web Programming (Java 2 Edition)",
"servlet programming", "JavaServer Pages", "JSP",
"Java alternatives to CGI", "server-side Java" };
String[] endings = { "?", "?", "?", "?!", "?!!!?" };
String[][] sentenceTemplates = { locations, actions, sources,
prepositions, subjects, endings };
String query = "";
for(int i=0; i<sentenceTemplates.length; i++) {
query = query + randomEntry(sentenceTemplates[i]);
}
return(query);
}
private String randomEntry(String[] strings) {
int index = (int)(Math.random()*strings.length);
return(strings[index]);
}
}
1.2 POST 数据发送与处理
当小程序使用 POST 方法发送数据时,有其独特的处理方式。与 GET 方法不同,POST 方法只能由小程序自身处理结果。以下是小程序发送 POST 数据并读取结果的 13 个步骤:
1.
创建 URL 对象
:
URL currentPage = getCodeBase();
String protocol = currentPage.getProtocol();
String host = currentPage.getHost();
int port = currentPage.getPort();
String urlSuffix = "/servlet/SomeServlet";
URL dataURL = new URL(protocol, host, port, urlSuffix);
- 创建 URLConnection 对象 :
URLConnection connection = dataURL.openConnection();
- 禁止浏览器缓存结果 :
connection.setUseCaches(false);
- 允许发送数据 :
connection.setDoOutput(true);
- 创建 ByteArrayOutputStream 缓冲数据 :
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(512);
- 附加输出流 :
PrintWriter out = new PrintWriter(byteStream, true);
- 将数据放入缓冲区 :
String val1 = URLEncoder.encode(someVal1);
String val2 = URLEncoder.encode(someVal2);
String data = "param1=" + val1 + "¶m2=" + val2;
out.print(data);
out.flush();
- 设置 Content-Length 头 :
connection.setRequestProperty("Content-Length", String.valueOf(byteStream.size()));
- 设置 Content-Type 头 :
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
- 发送实际数据 :
byteStream.writeTo(connection.getOutputStream());
- 打开输入流 :
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
- 读取结果 :
String line;
while((line = in.readLine()) != null) {
doSomethingWith(line);
}
-
完成操作
:这是一个相对机械的过程,你可以从
www.coreservlets.com下载示例作为起点。
以下是一个具体的小程序
SendPost.java
示例,它读取
firstName
、
lastName
和
emailAddress
参数,并通过 POST 方法发送到指定的主机、端口和 URI:
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
public class SendPost extends Applet implements ActionListener {
private LabeledTextField firstNameField, lastNameField,
emailAddressField, hostField,
portField, uriField;
private Button sendButton;
private TextArea resultsArea;
URL currentPage;
public void init() {
setBackground(Color.white);
setLayout(new BorderLayout());
Panel inputPanel = new Panel();
inputPanel.setLayout(new GridLayout(9, 1));
inputPanel.setFont(new Font("Serif", Font.BOLD, 14));
firstNameField = new LabeledTextField("First Name:", 15);
inputPanel.add(firstNameField);
lastNameField = new LabeledTextField("Last Name:", 15);
inputPanel.add(lastNameField);
emailAddressField = new LabeledTextField("Email Address:", 25);
inputPanel.add(emailAddressField);
Canvas separator1 = new Canvas();
inputPanel.add(separator1);
hostField = new LabeledTextField("Host:", 15);
hostField.getTextField().setEditable(false);
currentPage = getCodeBase();
String host = currentPage.getHost();
String resultsMessage = "Results will be shown here...";
if (host.length() == 0) {
resultsMessage = "Error: you must load this applet\n" +
"from a real Web server via HTTP,\n" +
"not from the local disk using\n" +
"a ’file:’ URL. It is fine,\n" +
"however, if the Web server is\n" +
"running on your local system.";
setEnabled(false);
}
hostField.getTextField().setText(host);
inputPanel.add(hostField);
portField = new LabeledTextField("Port (-1 means default):", 4);
String portString = String.valueOf(currentPage.getPort());
portField.getTextField().setText(portString);
inputPanel.add(portField);
uriField = new LabeledTextField("URI:", 40);
String defaultURI = "/servlet/coreservlets.ShowParameters";
uriField.getTextField().setText(defaultURI);
inputPanel.add(uriField);
Canvas separator2 = new Canvas();
inputPanel.add(separator2);
sendButton = new Button("Submit Data");
sendButton.addActionListener(this);
Panel buttonPanel = new Panel();
buttonPanel.add(sendButton);
inputPanel.add(buttonPanel);
add(inputPanel, BorderLayout.NORTH);
resultsArea = new TextArea();
resultsArea.setFont(new Font("Monospaced", Font.PLAIN, 14));
resultsArea.setText(resultsMessage);
add(resultsArea, BorderLayout.CENTER);
}
public void actionPerformed(ActionEvent event) {
try {
String protocol = currentPage.getProtocol();
String host = hostField.getTextField().getText();
String portString = portField.getTextField().getText();
int port;
try {
port = Integer.parseInt(portString);
} catch(NumberFormatException nfe) {
port = -1;
}
String uri = uriField.getTextField().getText();
URL dataURL = new URL(protocol, host, port, uri);
URLConnection connection = dataURL.openConnection();
connection.setUseCaches(false);
connection.setDoOutput(true);
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(512);
PrintWriter out = new PrintWriter(byteStream, true);
String postData =
"firstName=" + encodedValue(firstNameField) +
"&lastName=" + encodedValue(lastNameField) +
"&emailAddress=" + encodedValue(emailAddressField);
out.print(postData);
out.flush();
String lengthString = String.valueOf(byteStream.size());
connection.setRequestProperty("Content-Length", lengthString);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
byteStream.writeTo(connection.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
String linefeed = "\n";
resultsArea.setText("");
while((line = in.readLine()) != null) {
resultsArea.append(line);
resultsArea.append(linefeed);
}
} catch(IOException ioe) {
System.out.println("IOException: " + ioe);
}
}
private String encodedValue(LabeledTextField field) {
String rawValue = field.getTextField().getText();
return(URLEncoder.encode(rawValue));
}
}
1.3 绕过 HTTP 服务器
小程序虽然只能与加载它的同一台机器建立网络连接,但不一定需要连接到相同的端口(如 80 端口)。因此,小程序可以使用原始套接字、JDBC 或 RMI 与运行在服务器主机上的自定义客户端进行通信,其操作方式与普通 Java 程序相同。
2. JDBC 与数据库连接池
2.1 JDBC 概述
JDBC 提供了一个标准库,用于访问关系型数据库。使用 JDBC API,你可以使用相同的 Java 语法访问各种不同的 SQL 数据库。需要注意的是,JDBC 虽然标准化了连接数据库的机制、发送查询和提交事务的语法以及表示结果的数据结构,但并不试图标准化 SQL 语法。因此,你可以使用数据库供应商支持的任何 SQL 扩展。
2.2 使用 JDBC 的基本步骤
使用 JDBC 查询数据库有七个标准步骤:
1.
加载 JDBC 驱动
:通过
Class.forName
方法加载驱动类,避免硬编码类名。例如:
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
- 定义连接 URL :指定数据库的连接地址。例如:
String url = "jdbc:mysql://localhost:3306/mydatabase";
-
建立连接
:使用
DriverManager.getConnection方法建立与数据库的连接。例如:
Connection connection = DriverManager.getConnection(url, "username", "password");
-
创建语句对象
:使用
connection.createStatement()方法创建Statement对象。例如:
Statement statement = connection.createStatement();
-
执行查询或更新
:使用
statement.executeQuery或statement.executeUpdate方法执行 SQL 语句。例如:
ResultSet resultSet = statement.executeQuery("SELECT * FROM mytable");
-
处理结果
:遍历
ResultSet对象获取查询结果。例如:
while (resultSet.next()) {
String column1 = resultSet.getString("column1");
// 处理数据
}
-
关闭连接
:依次关闭
ResultSet、Statement和Connection对象。例如:
resultSet.close();
statement.close();
connection.close();
综上所述,Java 小程序与 Servlet 的交互以及 JDBC 数据库操作是 Java 开发中非常重要的部分。通过合理运用这些技术,我们可以开发出功能强大、高效稳定的 Java 应用程序。
Java 小程序与 Servlet 前端交互及 JDBC 数据库操作
3. 数据库连接池的作用与实现
在使用 JDBC 进行数据库操作时,频繁地创建和关闭数据库连接会带来较大的性能开销。数据库连接池就是为了解决这个问题而出现的,它可以预先创建一定数量的数据库连接,并将这些连接管理起来,当需要使用连接时,从连接池中获取,使用完毕后再将连接归还到连接池中,而不是直接关闭连接,这样可以大大提高数据库操作的性能。
3.1 连接池的优势
- 减少连接创建时间 :连接池中的连接是预先创建好的,当需要使用时可以直接获取,避免了每次都要进行创建连接的操作,从而减少了连接创建的时间开销。
- 降低系统资源消耗 :频繁地创建和关闭连接会占用大量的系统资源,而连接池可以复用连接,减少了系统资源的消耗。
- 提高响应速度 :由于连接池中的连接已经处于就绪状态,当有请求到来时,可以立即获取连接进行数据库操作,从而提高了系统的响应速度。
3.2 简单连接池的实现思路
以下是一个简单的数据库连接池的实现思路:
1.
初始化连接池
:在应用程序启动时,创建一定数量的数据库连接,并将这些连接存储在一个集合中。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class ConnectionPool {
private static final int INITIAL_POOL_SIZE = 5;
private static final String URL = "jdbc:mysql://localhost:3306/mydatabase";
private static final String USER = "username";
private static final String PASSWORD = "password";
private List<Connection> connectionPool;
public ConnectionPool() {
connectionPool = new ArrayList<>();
for (int i = 0; i < INITIAL_POOL_SIZE; i++) {
try {
Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
connectionPool.add(connection);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
- 获取连接 :当需要使用数据库连接时,从连接池中获取一个可用的连接。
public synchronized Connection getConnection() {
if (connectionPool.size() > 0) {
return connectionPool.remove(0);
}
return null;
}
- 归还连接 :当使用完数据库连接后,将连接归还到连接池中。
public synchronized void releaseConnection(Connection connection) {
connectionPool.add(connection);
}
}
- 使用连接池 :在应用程序中使用连接池进行数据库操作。
public class Main {
public static void main(String[] args) {
ConnectionPool connectionPool = new ConnectionPool();
Connection connection = connectionPool.getConnection();
if (connection != null) {
try {
// 执行数据库操作
} catch (Exception e) {
e.printStackTrace();
} finally {
connectionPool.releaseConnection(connection);
}
}
}
}
4. 实际应用中的注意事项
在实际应用中,使用 Java 小程序与 Servlet 交互以及 JDBC 数据库操作时,还需要注意以下几点:
4.1 安全性问题
-
输入验证
:在接收用户输入时,要进行严格的输入验证,防止 SQL 注入攻击。例如,在使用
Statement对象执行 SQL 语句时,如果直接将用户输入的内容拼接到 SQL 语句中,可能会导致 SQL 注入攻击。可以使用PreparedStatement对象来避免这个问题,因为它会对输入进行预编译,防止恶意输入。
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, username);
preparedStatement.setString(2, password);
ResultSet resultSet = preparedStatement.executeQuery();
- 权限管理 :对数据库连接的权限进行合理的管理,只给应用程序分配必要的权限,避免因权限过大而导致数据泄露或被篡改。
4.2 性能优化
-
批量操作
:在进行数据库插入或更新操作时,如果有大量的数据需要处理,可以使用批量操作来提高性能。例如,使用
PreparedStatement的addBatch和executeBatch方法。
String sql = "INSERT INTO users (username, password) VALUES (?, ?)";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
for (User user : userList) {
preparedStatement.setString(1, user.getUsername());
preparedStatement.setString(2, user.getPassword());
preparedStatement.addBatch();
}
preparedStatement.executeBatch();
- 索引优化 :对数据库表中的经常用于查询的字段创建索引,可以提高查询的速度。但要注意,索引也会带来一定的性能开销,因此要合理使用索引。
4.3 异常处理
在进行数据库操作时,要对可能出现的异常进行合理的处理,避免因异常导致程序崩溃。例如,在使用
Connection
、
Statement
和
ResultSet
时,要使用
try-catch-finally
语句来确保资源的正确关闭。
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = DriverManager.getConnection(url, username, password);
statement = connection.createStatement();
resultSet = statement.executeQuery("SELECT * FROM users");
while (resultSet.next()) {
// 处理结果
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (resultSet != null) resultSet.close();
if (statement != null) statement.close();
if (connection != null) connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
5. 总结
Java 小程序与 Servlet 的交互以及 JDBC 数据库操作是 Java 开发中非常重要的技术。通过合理运用这些技术,我们可以开发出功能强大、高效稳定的 Java 应用程序。在实际应用中,要注意安全性、性能优化和异常处理等问题,以确保应用程序的可靠性和稳定性。同时,数据库连接池的使用可以大大提高数据库操作的性能,是提高应用程序性能的重要手段之一。希望本文能够对大家在 Java 开发中使用这些技术有所帮助。
以下是一个简单的流程图,展示了使用 JDBC 进行数据库操作的基本流程:
graph TD;
A[加载 JDBC 驱动] --> B[定义连接 URL];
B --> C[建立连接];
C --> D[创建语句对象];
D --> E[执行查询或更新];
E --> F[处理结果];
F --> G[关闭连接];
通过以上的介绍,我们对 Java 小程序与 Servlet 前端交互以及 JDBC 数据库操作有了更深入的了解。在实际开发中,我们可以根据具体的需求,灵活运用这些技术,开发出优秀的 Java 应用程序。
超级会员免费看

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



