35、Java 小程序与 Servlet 前端交互及 JDBC 数据库操作

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);
  1. 创建 URLConnection 对象
URLConnection connection = dataURL.openConnection();
  1. 禁止浏览器缓存结果
connection.setUseCaches(false);
  1. 允许发送数据
connection.setDoOutput(true);
  1. 创建 ByteArrayOutputStream 缓冲数据
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(512);
  1. 附加输出流
PrintWriter out = new PrintWriter(byteStream, true);
  1. 将数据放入缓冲区
String val1 = URLEncoder.encode(someVal1);
String val2 = URLEncoder.encode(someVal2);
String data = "param1=" + val1 + "&param2=" + val2;
out.print(data);
out.flush();
  1. 设置 Content-Length 头
connection.setRequestProperty("Content-Length", String.valueOf(byteStream.size()));
  1. 设置 Content-Type 头
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
  1. 发送实际数据
byteStream.writeTo(connection.getOutputStream());
  1. 打开输入流
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
  1. 读取结果
String line;
while((line = in.readLine()) != null) {
    doSomethingWith(line);
}
  1. 完成操作 :这是一个相对机械的过程,你可以从 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();
}
  1. 定义连接 URL :指定数据库的连接地址。例如:
String url = "jdbc:mysql://localhost:3306/mydatabase";
  1. 建立连接 :使用 DriverManager.getConnection 方法建立与数据库的连接。例如:
Connection connection = DriverManager.getConnection(url, "username", "password");
  1. 创建语句对象 :使用 connection.createStatement() 方法创建 Statement 对象。例如:
Statement statement = connection.createStatement();
  1. 执行查询或更新 :使用 statement.executeQuery statement.executeUpdate 方法执行 SQL 语句。例如:
ResultSet resultSet = statement.executeQuery("SELECT * FROM mytable");
  1. 处理结果 :遍历 ResultSet 对象获取查询结果。例如:
while (resultSet.next()) {
    String column1 = resultSet.getString("column1");
    // 处理数据
}
  1. 关闭连接 :依次关闭 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();
            }
        }
    }
  1. 获取连接 :当需要使用数据库连接时,从连接池中获取一个可用的连接。
    public synchronized Connection getConnection() {
        if (connectionPool.size() > 0) {
            return connectionPool.remove(0);
        }
        return null;
    }
  1. 归还连接 :当使用完数据库连接后,将连接归还到连接池中。
    public synchronized void releaseConnection(Connection connection) {
        connectionPool.add(connection);
    }
}
  1. 使用连接池 :在应用程序中使用连接池进行数据库操作。
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 应用程序。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值