【Java】在一個前臺界面中動態展示多個數據表的字段及數據

企業的生產環境中,如果不允許直接操作數據表中的數據,則需要開發一個前臺界面,在必要時實現對多個數據表中數據的增刪改查, 此時就需要后端將Oracle表字段及數據查詢返回前端動態展示……

一、Oracle特定元數據查詢

  1. 使用JDBC獲取Oracle表字段信息
public List<String> getOracleTableColumns(String tableName) throws SQLException {List<String> columns = new ArrayList<>();try (Connection conn = dataSource.getConnection()) {// Oracle元數據查詢DatabaseMetaData metaData = conn.getMetaData();// Oracle注意: 表名需要大寫ResultSet rs = metaData.getColumns(null, conn.getSchema(), tableName.toUpperCase(), null);while (rs.next()) {columns.add(rs.getString("COLUMN_NAME"));}}return columns;
}
  1. 獲取Oracle字段詳細信息(含數據類型)
public List<ColumnMeta> getOracleTableMetaData(String tableName) throws SQLException {List<ColumnMeta> columns = new ArrayList<>();try (Connection conn = dataSource.getConnection()) {DatabaseMetaData metaData = conn.getMetaData();ResultSet rs = metaData.getColumns(null, conn.getSchema(), tableName.toUpperCase(), null);while (rs.next()) {ColumnMeta meta = new ColumnMeta();meta.setColumnName(rs.getString("COLUMN_NAME"));meta.setDataType(rs.getString("TYPE_NAME"));meta.setColumnSize(rs.getInt("COLUMN_SIZE"));meta.setNullable("YES".equals(rs.getString("IS_NULLABLE")));meta.setRemarks(rs.getString("REMARKS")); // 列注釋columns.add(meta);}}return columns;
}@Data
class ColumnMeta {private String columnName;private String dataType;private int columnSize;private boolean nullable;private String remarks;
}

二、Oracle表數據查詢方案

  1. 通用數據查詢DTO
@Data
public class OracleTableDataDTO {private String tableName;private List<ColumnMeta> columnMetas;private List<Map<String, Object>> rows;private Pagination pagination; // 分頁信息
}@Data
class Pagination {private int total;private int page;private int pageSize;
}
  1. 使用JDBC查詢Oracle表數據
public OracleTableDataDTO getOracleTableData(String tableName, int page, int pageSize) {OracleTableDataDTO dto = new OracleTableDataDTO();dto.setTableName(tableName);try (Connection conn = dataSource.getConnection()) {// 1. 獲取列元數據List<ColumnMeta> columns = getOracleTableMetaData(tableName);dto.setColumnMetas(columns);// 2. 構建分頁SQL (Oracle分頁語法)String sql = "SELECT * FROM (SELECT a.*, ROWNUM rn FROM (" +"SELECT * FROM " + tableName + ") a WHERE ROWNUM <= ?) WHERE rn > ?";// 3. 計算分頁參數int start = (page - 1) * pageSize;int end = page * pageSize;// 4. 執行查詢List<Map<String, Object>> rows = new ArrayList<>();try (PreparedStatement stmt = conn.prepareStatement(sql)) {stmt.setInt(1, end);stmt.setInt(2, start);ResultSet rs = stmt.executeQuery();ResultSetMetaData rsMeta = rs.getMetaData();while (rs.next()) {Map<String, Object> row = new LinkedHashMap<>();for (int i = 1; i <= rsMeta.getColumnCount(); i++) {String colName = rsMeta.getColumnName(i);Object value = rs.getObject(i);// 處理Oracle特定類型if (value instanceof oracle.sql.TIMESTAMP) {value = ((oracle.sql.TIMESTAMP)value).timestampValue();} else if (value instanceof oracle.sql.CLOB) {value = ((oracle.sql.CLOB)value).getSubString(1, (int)((oracle.sql.CLOB)value).length());}row.put(colName, value);}rows.add(row);}}dto.setRows(rows);// 5. 獲取總記錄數int total = getOracleTableCount(conn, tableName);dto.setPagination(new Pagination(total, page, pageSize));} catch (SQLException e) {throw new RuntimeException("查詢Oracle表數據失敗", e);}return dto;
}private int getOracleTableCount(Connection conn, String tableName) throws SQLException {String sql = "SELECT COUNT(*) FROM " + tableName;try (PreparedStatement stmt = conn.prepareStatement(sql);ResultSet rs = stmt.executeQuery()) {return rs.next() ? rs.getInt(1) : 0;}
}

三、Spring Boot控制器實現
RESTful API接口

@RestController
@RequestMapping("/api/oracle")
public class OracleTableController {@Autowiredprivate OracleTableService tableService;@GetMapping("/{tableName}/metadata")public ResponseEntity<List<ColumnMeta>> getTableMetadata(@PathVariable String tableName) {try {return ResponseEntity.ok(tableService.getOracleTableMetaData(tableName));} catch (SQLException e) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();}}@GetMapping("/{tableName}/data")public ResponseEntity<OracleTableDataDTO> getTableData(@PathVariable String tableName,@RequestParam(defaultValue = "1") int page,@RequestParam(defaultValue = "10") int pageSize) {// 表名安全檢查if (!isValidTableName(tableName)) {return ResponseEntity.badRequest().build();}return ResponseEntity.ok(tableService.getOracleTableData(tableName, page, pageSize));}private boolean isValidTableName(String tableName) {// 實現表名白名單驗證return tableName.matches("[A-Za-z0-9_]+");}
}

四、前端展示方案
Vue.js動態表格組件

<template><div><h2>{{ tableName }} 表數據</h2><!-- 字段元數據展示 --><div class="metadata" v-if="columnMetas.length"><h3>表結構</h3><table class="meta-table"><thead><tr><th>列名</th><th>類型</th><th>長度</th><th>可空</th><th>注釋</th></tr></thead><tbody><tr v-for="col in columnMetas" :key="col.columnName"><td>{{ col.columnName }}</td><td>{{ col.dataType }}</td><td>{{ col.columnSize }}</td><td>{{ col.nullable ? '是' : '否' }}</td><td>{{ col.remarks || '-' }}</td></tr></tbody></table></div><!-- 數據展示 --><div class="data-table"><h3>表數據 ({{ pagination.total }})</h3><table><thead><tr><th v-for="col in columnMetas" :key="col.columnName">{{ col.columnName }}</th></tr></thead><tbody><tr v-for="(row, index) in rows" :key="index"><td v-for="col in columnMetas" :key="col.columnName">{{ formatValue(row[col.columnName]) }}</td></tr></tbody></table><!-- 分頁控件 --><div class="pagination"><button @click="prevPage" :disabled="pagination.page <= 1">上一頁</button><span>{{ pagination.page }}/{{ totalPages }}</span><button @click="nextPage" :disabled="pagination.page >= totalPages">下一頁</button></div></div></div>
</template><script>
export default {data() {return {tableName: '',columnMetas: [],rows: [],pagination: {total: 0,page: 1,pageSize: 10}};},computed: {totalPages() {return Math.ceil(this.pagination.total / this.pagination.pageSize);}},methods: {async loadTableData() {try {// 加載元數據const metaRes = await this.$axios.get(`/api/oracle/${this.tableName}/metadata`);this.columnMetas = metaRes.data;// 加載數據const dataRes = await this.$axios.get(`/api/oracle/${this.tableName}/data`, {params: {page: this.pagination.page,pageSize: this.pagination.pageSize}});const data = dataRes.data;this.rows = data.rows;this.pagination = data.pagination;} catch (error) {console.error('加載表數據失敗:', error);}},formatValue(value) {if (value === null || value === undefined) return 'NULL';if (value instanceof Object) return JSON.stringify(value);return value;},prevPage() {if (this.pagination.page > 1) {this.pagination.page--;this.loadTableData();}},nextPage() {if (this.pagination.page < this.totalPages) {this.pagination.page++;this.loadTableData();}}},mounted() {this.tableName = this.$route.params.tableName;this.loadTableData();}
};
</script><style scoped>
/* 添加適當的表格樣式 */
table {width: 100%;border-collapse: collapse;
}
th, td {border: 1px solid #ddd;padding: 8px;
}
th {background-color: #f2f2f2;
}
.meta-table {margin-bottom: 20px;
}
.pagination {margin-top: 15px;
}
</style>

五、Oracle特定處理注意事項
數據類型處理:

// 特殊處理Oracle類型
if (value instanceof oracle.sql.TIMESTAMP) {value = ((oracle.sql.TIMESTAMP)value).timestampValue();
}
if (value instanceof oracle.sql.BLOB) {value = "[BLOB]";
}
if (value instanceof oracle.sql.CLOB) {value = ((oracle.sql.CLOB)value).getSubString(1, 1000); // 限制CLOB讀取長度
}

表名大小寫問題:

// Oracle默認表名是大寫的
String normalizedTableName = tableName.toUpperCase();

性能優化:

// 使用Oracle的ROWID快速分頁
String sql = "SELECT * FROM " + tableName + " WHERE ROWID IN (SELECT RID FROM (" +"   SELECT ROWID AS RID, ROWNUM AS RN FROM " + tableName +"   WHERE ROWNUM <= ?) WHERE RN > ?)";

長文本處理:

// 對于CLOB字段,限制讀取長度
if ("CLOB".equals(columnType)) {stmt.setCharacterStream(i, reader, 1024); // 限制讀取1K字符
}

六、安全增強措施
SQL注入防護:

// 表名白名單驗證
private static final Set<String> ALLOWED_TABLES = Set.of("EMPLOYEES", "DEPARTMENTS");public void validateTableName(String tableName) {if (!ALLOWED_TABLES.contains(tableName.toUpperCase())) {throw new IllegalArgumentException("不允許訪問該表");}
}

敏感字段過濾:

// 過濾掉密碼等敏感字段
columns.removeIf(col -> SENSITIVE_COLUMNS.contains(col.toUpperCase()));

數據脫敏:

// 對敏感數據進行脫敏處理
if (columnName.toUpperCase().contains("PASSWORD")) {row.put(columnName, "******");
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/94014.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/94014.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/94014.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MySQL(174)如何理解MySQL的多版本并發控制(MVCC)?

MySQL的多版本并發控制&#xff08;MVCC, Multi-Version Concurrency Control&#xff09;是一種用于實現高并發性的機制&#xff0c;它允許多個事務同時讀取和寫入數據&#xff0c;而不會相互阻塞。MVCC主要在InnoDB存儲引擎中實現&#xff0c;通過維護數據的多個版本來實現一…

Docker--將非root用戶添加docker用戶組,解決頻繁sudo執行輸入密碼的問題

一、為什么要有docker用戶組&#xff1f; 根本原因&#xff1a; Linux的設備訪問權限控制機制 Docker守護進程&#xff08;dockerd&#xff09;運行時會創建一個特殊的Unix套接字文件&#xff0c;如&#xff1a;/var/run/docker.sock。 這個文件就像一個“門”&#xff0c;所有…

C語言---函數的遞歸與迭代

遞歸的理解與限制條件 所謂函數遞歸就是遞推加回歸的過程&#xff0c;就是函數自己調用自己。遞歸的思想就是把復雜的問題拆分成與原來那個大問題相似的子問題來求解&#xff0c;大事化小&#xff0c;像剝洋蔥一樣&#xff0c;最終把問題解決。 遞歸的限制條件&#xff1a; 一個…

freqtrade在docker運行一個dryrun實例

檢查配置 freqtrade trade --config user_data/config.json --strategy MlStrategy config文件,這個配置做期貨為主&#xff0c;靜態配置了交易對&#xff0c;同時端口和第一個bot要不一樣&#xff0c;不然沒有辦法進行監控&#xff0c;甚至要沖突了。10S鐘進行循環&#xff0c…

單片機學習筆記.PWM

PWM原理&#xff1a; 頻率占空比&#xff1a;精度占空比變化步距 電機驅動電路&#xff1a;利用PWM實現呼吸燈代碼 sbit LEDP2^0;//引腳定義unsigned char Time,i;//變量定義void Delay(unsigned int t)//定義延時 {while(t--); }main函數里&#xff1a;int main() {unsigned c…

【Git】解決使用SSH連接遠程倉庫時需要多次輸入密碼的問題

問題產生的原因&#xff1a;你的SSH私鑰設置了密碼短語&#xff08;passphrase&#xff09;。解決問題的方法&#xff1a;使用SSH代理&#xff08;ssh-agent&#xff09;&#xff0c;ssh-agent是一個后臺運行程序&#xff0c;它會記住你解鎖過的SSH私鑰的密碼短語&#xff0c;這…

機器學習—邏輯回歸

一介紹邏輯回歸是處理二分類問題的線性模型&#xff0c;通過sigmoid函數將線性輸出映射到[0,1]&#xff0c;輸出事件發生概率&#xff0c;廣泛用于預測與分類。如果做坐標的話&#xff0c;特征就是p1和p2&#xff0c;結果就是y紅的與綠的 二Sigma函數代碼說明Sigmoid 函數定義&…

深入解讀OpenTelemetry分布式鏈路追蹤:原理與實踐指南

深入解讀OpenTelemetry分布式鏈路追蹤&#xff1a;原理與實踐指南 分布式系統在微服務架構下&#xff0c;服務調用鏈越來越復雜&#xff0c;追蹤單次請求在各個微服務之間的執行情況成為運維與性能優化的關鍵。作為新一代開源標準&#xff0c;OpenTelemetry為分布式追蹤、指標與…

【0基礎PS】PS工具詳解--圖案圖章工具

目錄前言一、圖案圖章工具基礎認知?二、工具選項欄參數詳解?三、圖案圖章工具應用案例?總結前言 在 Adobe Photoshop 這一強大的圖像處理軟件中&#xff0c;圖案圖章工具是一個獨具特色的功能&#xff0c;它允許用戶利用預先定義好的圖案進行繪畫操作。 一、圖案圖章工具基…

劇本殺小程序系統開發:構建數字化劇本殺生態圈

在快節奏的現代生活中&#xff0c;人們越來越渴望在閑暇之余找到一種既能放松心情又能增進社交的方式。劇本殺&#xff0c;作為一種集推理、表演、社交于一體的新興娛樂形式&#xff0c;恰好滿足了這一需求。然而&#xff0c;隨著市場的不斷擴大&#xff0c;如何保持劇本殺的新…

【DL學習筆記】計算圖與自動求導

計算圖計算圖&#xff08;Computation Graph&#xff09;是一種用于描述計算過程的圖形化表示方法。在深度學習中&#xff0c;計算圖通常用于描述 網絡結構、運算過程 和數據流向。計算圖是一種有向無環圖&#xff0c;用圖形方式來表示算子與變量之間的關系&#xff0c;直觀高效…

大型地面光伏電站開發建設流程

?地面電站特特點&#xff1a;規模大&#xff0c;通常占用土地、水面等&#xff0c;地面式選址選項多&#xff0c;且不斷拓展出新的用地模式&#xff0c;地面式選址集中在山體、灘涂、沼澤、戈壁、沙漠、受污染土地等閑置或廢棄土地上。

除數博弈(動態規劃)

愛麗絲和鮑勃一起玩游戲&#xff0c;他們輪流行動。愛麗絲先手開局。最初&#xff0c;黑板上有一個數字 n 。在每個玩家的回合&#xff0c;玩家需要執行以下操作&#xff1a;選出任一 x&#xff0c;滿足 0 < x < n 且 n % x 0 。用 n - x 替換黑板上的數字 n 。如果玩家…

一起學springAI系列一:初體驗

Spring AI是干嘛的官網最權威&#xff0c;直接粘貼&#xff1a;“Spring AI”項目旨在簡化那些包含人工智能功能的應用程序的開發過程&#xff0c;同時避免不必要的復雜性。AI相關領域的功能對python的支持是最好的&#xff0c;相關供應商在出了啥功能的時候&#xff0c;都會優…

Ext JS極速項目之 Coworkee

ExtJS Coworkee 是什么? Ext JS 的 Coworkee 是一個由 Sencha 官方提供的完整員工管理應用示例,旨在展示 Ext JS 框架在企業級應用開發中的能力。 在線試用的地址是: https://examples.sencha.com/coworkee/#home 頁面效果與布局 登錄頁面: 主頁效果 左右分區結構:左…

飛算科技:原創技術重塑 Java 開發,引領行業數智化新浪潮

在科技革新的浪潮中&#xff0c;飛算科技作為一家堅持自主創新的數字科技企業&#xff0c;同時也是國家級高新技術企業&#xff0c;正深耕互聯網科技、大數據、人工智能等前沿領域&#xff0c;為眾多企業的數字化與智能化轉型提供強勁動力。?飛算科技的成長軌跡&#xff0c;是…

cesium FBO(一)渲染到紋理(RTT)

一聽到三維的RTT&#xff08;Render To Texture&#xff09;&#xff0c;似乎很神秘&#xff0c;但從底層實現一看&#xff0c;其實也就那樣&#xff0c;設計API的哪些頂級家伙已經幫你安排的明明白白了&#xff0c;咱們只需要學會怎么用就可以了。我認為得從WebGL入手&#xf…

PNP機器人機器人學術年會展示靈巧手動作捕捉方案。

2025年8月1-3日&#xff0c;第六屆中國機器人學術年會&#xff08;CCRS2025&#xff09;在長沙國際會議中心舉行&#xff0c;主題“人機共融&#xff0c;智向未來”。PNP機器人與靈巧智能聯合展出最新靈巧手模仿學習方案&#xff1a;基于少量示教數據即可快速復現復雜抓取動作&…

【45】C#入門到精通——C#調用C/C++生成動態庫.dll及C++ 生成動態庫.dll ,DllImport()方式導入 C++動態庫.dll方法總結

文章目錄1 C 生成動態庫.dll2 C#調用C/C生成動態庫.dll2.1 [DllImport()] 方式導入 C動態庫.dll2.2 調用測試3 C/C 生成通用dll,改進3.1改進后.h3.2 .cpp3.2 C# 調用4 [DllImport()] 方式導入C生成的 .dll 總結4.1 指定路徑導入4.2 .dll放在 執行目錄下&#xff08;一定要放對&…

從協議棧到ath12k_mac_op_tx的完整調用路徑

文章目錄 從協議棧到ath12k_mac_op_tx的完整調用路徑 1. 整體架構概覽 2. 詳細調用路徑分析 2.1 應用層到Socket層 2.2 協議層處理 2.3 網絡設備層到mac80211 2.4 mac80211發送入口 2.5 mac80211核心發送處理 2.6 mac80211發送核心處理 2.7 mac80211發送調度 2.8 最終驅動調用 …