本篇将先前的表格输出修改为前后端分离架构,前端采用React框架实现,IDE使用VSCode。

React前端代码

在web项目同一目录下创建新的文件夹命名为WebReact。

在终端cd到WebReact目录下执行代码创建出React框架。

在index.js里配置路由:

import React from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import ReactDOM from 'react-dom/client';
import locale from 'antd/locale/zh_CN';
import { ConfigProvider } from 'antd';
import App from './App.js'; 
const sys = React.sys;
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  //不能加这个StrictMode,否则组件的componentDidMount会执行两次
  // <React.StrictMode>
  <BrowserRouter>
    {/* <LocaleProvider locale={zh_CN}> */}
    <ConfigProvider locale={locale}>
      <Routes>
        <Route key="App" path="/*" element={<App />} />
        <Route key="fileupload" path="fileupload/*" element={React.createElement(require("./FileUpload").default)} />
      </Routes>
      {/* <Login /> */}
    </ConfigProvider>
    {/* </LocaleProvider> */}
  </BrowserRouter>
  // </React.StrictMode>
);

这里App.js用于显示表格,代码如下:

import React, { Component } from "react";

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      products: [],     // 存放后端返回的数据
      loading: true,    // 加载状态
      error: null       // 错误信息
    };
  }

  // 生命周期钩子:组件挂载后调用后端接口
  componentDidMount() {
    // 后端 Servlet 返回 JSON 的接口地址(请改成你自己的项目路径)
    const apiUrl = "http://localhost:8080/MyWeb/api/products";

    fetch(apiUrl)
      .then((response) => {
        if (!response.ok) {
          throw new Error("网络响应失败: " + response.status);
        }
        return response.json();
      })
      .then((data) => {
        this.setState({ products: data, loading: false });
      })
      .catch((error) => {
        console.error("请求出错:", error);
        this.setState({ error, loading: false });
      });
  }

  render() {
    const { products, loading, error } = this.state;

    if (loading) {
      return <p style={{ padding: "20px" }}>正在加载数据,请稍候...</p>;
    }

    if (error) {
      return (
        <p style={{ padding: "20px", color: "red" }}>
          数据加载失败:{error.message}
        </p>
      );
    }

    return (
      <div style={{ padding: "30px", fontFamily: "Arial" }}>
        <h2>商品信息列表</h2>

        <table
          border="1"
          cellPadding="8"
          style={{ borderCollapse: "collapse", width: "100%" }}
        >
          <thead style={{ backgroundColor: "#f5f5f5" }}>
            <tr>
              <th>商品编号</th>
              <th>品牌</th>
              <th>型号</th>
              <th>价格(元)</th>
            </tr>
          </thead>

          <tbody>
            {products.map((p, index) => (
              <tr key={index}>
                <td>{p.pid}</td>
                <td>{p.brand}</td>
                <td>{p.model}</td>
                <td>{p.price}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    );
  }
}


FileUpload.js用于文件上传,代码如下:

import React, { Component } from "react";

class FileUpload extends Component {
  constructor(props) {
    super(props);
    this.state = {
      selectedFile: null,
      uploading: false,
      message: "",
    };
  }

  handleFileChange = (e) => {
    this.setState({ selectedFile: e.target.files[0], message: "" });
  };

  handleUpload = (e) => {
    e.preventDefault();
    const { selectedFile } = this.state;
    if (!selectedFile) {
      this.setState({ message: "⚠️ 请先选择文件!" });
      return;
    }

    const formData = new FormData();
    formData.append("myfile", selectedFile);

    this.setState({ uploading: true, message: "正在上传,请稍候..." });

    fetch("http://localhost:8080/MyWeb/upload", {
      method: "POST",
      body: formData,
    })
      .then((res) => {
        if (!res.ok) {
          throw new Error("状态码:" + res.status);
        }
        return res.json(); // ✅ 改成 JSON
      })
      .then((data) => {
        if (data.success) {
          this.setState({
            uploading: false,
            message: `上传成功!文件名:${data.fileName}`,
          });
        } else {
          this.setState({
            uploading: false,
            message: `上传失败:${data.message}`,
          });
        }
      })
      .catch((err) => {
        this.setState({
          uploading: false,
          message: "上传出错:" + err.message,
        });
      });
  };

  render() {
    const { selectedFile, message, uploading } = this.state;

    return (
      <div style={{ padding: "40px", fontFamily: "Arial" }}>
        <h2>📂 文件上传系统</h2>

        <form onSubmit={this.handleUpload}>
          <input type="file" onChange={this.handleFileChange} />
          <br />
          <br />
          <button
            type="submit"
            disabled={uploading}
            style={{
              padding: "8px 16px",
              backgroundColor: uploading ? "#999" : "#007bff",
              color: "#fff",
              border: "none",
              borderRadius: "4px",
              cursor: uploading ? "not-allowed" : "pointer",
            }}
          >
            {uploading ? "正在上传..." : "上传文件"}
          </button>
        </form>

        {selectedFile && (
          <p style={{ marginTop: "15px" }}>
            已选择文件:<strong>{selectedFile.name}</strong>
          </p>
        )}

        {message && (
          <p
            style={{
              marginTop: "20px",
              color: message.includes("✅") ? "green" : "red",
              fontWeight: "bold",
            }}
          >
            {message}
          </p>
        )}
      </div>
    );
  }
}

export default FileUpload;

Servlet后端代码

后端productsInfo的servlet如下:

package MyWork.chp03.servlet;

import MyWork.chp03.entity.Product;
import MyWork.chp03.dao.ProductDao;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.util.List;

// 建议统一小写命名,接口路径改为 /api/products 以符合REST风格
@WebServlet(name = "productsInfo", value = "/api/products")
public class productsInfo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // ===== 允许跨域 (React 前端默认端口是3000) =====
        response.setHeader("Access-Control-Allow-Origin", "http://localhost:3000");
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type");
        response.setContentType("application/json;charset=UTF-8");

        PrintWriter out = response.getWriter();

        try {
            // ===== 查询数据库 =====
            ProductDao productDao = new ProductDao();
            List<Product> products = productDao.selectAll();

            // ===== 转换为 JSON 格式 =====
            // 你可以使用简单的手工拼接(或用 Gson)
            StringBuilder json = new StringBuilder("[");
            for (int i = 0; i < products.size(); i++) {
                Product p = products.get(i);
                json.append("{")
                        .append("\"pid\":\"").append(p.getPid()).append("\",")
                        .append("\"brand\":\"").append(p.getBrand()).append("\",")
                        .append("\"model\":\"").append(p.getModel()).append("\",")
                        .append("\"price\":").append(p.getPrice())
                        .append("}");
                if (i < products.size() - 1) {
                    json.append(",");
                }
            }
            json.append("]");

            // =====  输出 JSON 给前端 =====
            out.print(json.toString());
            out.flush();

        } catch (SQLException e) {
            e.printStackTrace();
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            out.print("{\"error\": \"Database query failed.\"}");
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}
后端ExcelServlet的servlet如下:
package MyWork.chp03.servlet;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.*;

@WebServlet("/excelDemo")
public class ExcelServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("application/vnd.ms-excel;charset=UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=data.xls");

        PrintWriter out = response.getWriter();
        out.println("编号\t姓名\t成绩");
        out.println("1\t张三\t90");
        out.println("2\t李四\t85");
        out.println("3\t王五\t88");

        out.flush();
        out.close();
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

前端表格界面

前端上传文件界面

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐