寫在前面
之前開發的時候需要實現excel表格文件的共享功能,並且是同一張大表格,不同的人只能看裏面的一部分數據。由於數據每天更新,且每次都要手動篩選出給不同的人看的數據。很是繁瑣。希望能有一個方便的方法來實現:維護這個數據大表的人只需要更新這張表,其他人就可以自己隨時獲取自己有權查看的那部分數據。
也許你有更好更簡單的方法來實現。歡迎留言我。作爲初學者寫這篇文字只是記錄一下我解決問題的過程。因爲這裏涉及到了Oracle數據庫的操作,javaEE、jsp的編寫,前臺HTML、javascript、DOM 的操作,等方面。方便今後忘了的時候自己翻閱。
下面是正文。
方案一、使用數據庫+plsqldev (.xlsx)
首先我想到的是將這個數據大表(一個.xlsx文件),轉換成數據表,存入數據庫中(我這裏使用的是Oracle(這不是重點)
),然後創建view,並設置列名爲原 .xlsx 文件的列名。
維護數據的人只要在更新數據的時候使用 plsqldev 獨立版(無需安裝Oracle客戶端即可使用的版本),執行下面的sql:
select * from TABLENAME order by ID for update;
-- 這裏若不使用“order by ID”,有可能結果不是按照當初導入的順序呈現的。
將自己的excel文件複製粘貼到數據庫即可。然後想要查看的人查詢自己的view,並使用 plsqldev 的導出到 .xlsx 功能即可導出。
優點:簡單粗暴。使用者會使用 plsqldev 即可操作,而且實現了權限隔離,無法查看無權查看的數據的功能需求。
缺點:1.使用者不同的電腦環境 配置 plsqldev 時會出現各種情況,需要處理並且很棘手、2.用戶體驗差、3.使用時需要學習成本,學習如何使用 plsqldev 。
//無源碼
方案二、使用數據庫+jsp(.csv)
同樣是使用數據庫將表格數據遷移至數據庫裏,在服務器端使用 jsp 來實現 數據從數據庫導出到 .csv 的功能。在 jsp 設置參數判斷用戶的權限,來導出對應是view數據。並呈現給用戶。先說說這樣做的優缺點。
優點:實現了權限隔離,無法查看無權查看的數據的功能需求。簡單粗暴用戶只需一個鏈接即可下載到自己所需的 .csv 文件。
缺點:1.呈現的爲 .csv 文件,無發保存表格的樣式,體驗稍差。2.用戶需要自己調節樣式並另存爲 .xlsx 才能保存表格的樣式,然而畢竟會用戶不會操作,造成體驗差。
實現的源碼如下:
<%@page import="com.tltable.jdbc.tltableDAO"%>
<%@ page language="java" pageEncoding="UTF-8"%>
<%!String sql = "select * from TABLENAME order by u_uid";
// 這只是個demo,做測試。
//可以通過傳參實現執行不同的 sql 來查詢不同的 table (view)
String[][] value = tltableDAO.selectToArray(sql);
// tltableDAO.selectToArray 函數執行 sql 並將返回結果轉換爲數組的格式。
String csvStr = this.ArrayToCsvstr(value);
public String ArrayToCsvstr(String[][] value) {
String csvstr = "";
for (int j = 0; j < value.length; j++) {
if (value[j] == null) {
csvstr = "獲取值爲空。";
break;
}
for (int i = 0; i < value[j].length; i++) {
csvstr += value[j][i] + ",";
}
csvstr += "\n";
}
return csvstr;
}
%>
<%
response.setHeader("Content-type", "application/octet-stream;charset=GBK");
//之前沒有加 charset=GBK ,默認的 UTF-8 下載下來用excel打開會是亂碼。
response.setHeader("Content-Disposition", "attachment; filename=\"my-data.csv\"");//生成的csv名爲my-data.csv。也可以設置爲動態的文件名。
//String data = request.getParameter("csv_text");
out.println(csvStr);//把數據寫入到瀏覽器,以下載的方式
// 當然在輸出之前可以在 csvStr 前添加一行表數據的列名。增加用戶體驗。
%>
tltableDAO.selectToArray 代碼:
/**
* 查詢數據庫,並轉化成 String[][]
*
* @param sql
* @param args
* @return
*/
public static String[][] selectToArray(String sql, Object... args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultset = null;
String[][] aaa = null;
try {
connection = JDBCTools.getConnection();
preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
preparedStatement.setObject(i + 1, args[i]);
}
resultset = preparedStatement.executeQuery();
aaa = tltableDAO.getColumnValues(resultset);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCTools.releaseDB(resultset, preparedStatement, connection);
}
return aaa;
}
//這裏涉及的 JDBCTools.java 我想網上會有很多的。我就不貼出來了
方案三、使用數據庫+僞靜態HTML(.csv 或 .xlsx)
這個方案我認爲是最好的了。當然也是我花了很長時間纔想到的。基於方案一 方案二的弊端,本方案做了儘可能的兼容並提升了用戶體驗。
在方案二中我們可以將數據庫的數據轉換成數組,本方案則是將數組推送到 web 前端。這樣一來,可以實現
1、 以<table>
的形式呈現出來
IE10+以及其他新版瀏覽器可以使用 handsontable 插件來實現大數據表格在 前端的完美呈現。 反正我覺得用戶不需要。就沒研究。感興趣的可自己去官網查看。handsontable官網
用戶可直接查看(我感覺沒必要)。且客戶端瀏覽器參差不齊,我公司基本使用的都是IE8。╮(╯▽╰)╭ IE8 太多效果沒法呈現。
2、 使用 JavaScript 配合使用 IE 的 ActiveXObject 調用 Excel 導出數據到 Excel
前提是電腦上安裝了 Office 的 excel 。源碼如下:
<a href="#" onclick="downloaddata_ie('testtable')">IE導出</a>
function downloaddata_ie(tableid) {
var curTbl = document.getElementById(tableid);
var oXL = new ActiveXObject("Excel.Application");//創建AX對象excel
var oWB = oXL.Workbooks.Add();//獲取workbook對象
var oSheet = oWB.ActiveSheet;//激活當前sheet
var Lenr = curTbl.rows.length;//取得表格行數
for (i = 0; i < Lenr; i++) {
var Lenc = curTbl.rows(i).cells.length;//取得每行的列數
for (j = 0; j < Lenc; j++) {
oSheet.Cells(i + 1, j + 1).value = curTbl.rows(i).cells(j).innerText;//賦值
}
}
oXL.Visible = true;//設置excel可見屬性
}
或者下面的代碼會自動在 excel 中彈出保存對話框,且使用的非賦值操作而是複製操作:
var idTmr;
function saveAsXlsx(tableid,filename) {// 整個表格拷貝到EXCEL中
var curTbl = document.getElementById(tableid);
var oXL = new ActiveXObject("Excel.Application");
// 創建AX對象excel
var oWB = oXL.Workbooks.Add();
// 獲取workbook對象
var xlsheet = oWB.Worksheets(1);
// 激活當前sheet
var sel = document.body.createTextRange();
sel.moveToElementText(curTbl);
// 把表格中的內容移到TextRange中
sel.select();
// 全選TextRange中內容
sel.execCommand("Copy");
// 複製TextRange中內容
xlsheet.Paste();
// 粘貼到活動的EXCEL中
oXL.Visible = true;
// 設置excel可見屬性
try {
var fname = oXL.Application.GetSaveAsFilename(filename+".xlsx",
"Excel Spreadsheets (*.xlsx), *.xls11");
} catch (e) {
print("Nested catch caught " + e);
} finally {
oWB.SaveAs(fname);
oWB.Close(savechanges = false);
// xls.visible = false;
oXL.Quit();
oXL = null;
// 結束excel進程,退出完成
// window.setInterval("Cleanup();",1);
idTmr = window.setInterval("Cleanup();", 1);
}
}
function Cleanup() {
window.clearInterval(idTmr);
CollectGarbage();
}
3、 非 IE 瀏覽器 只能生成 .csv 文件供用戶下載
可以繼續使用 jsp 的方案,也可以使用 web 前端 的解決方案。
web 前端 解決方案 源碼:
<a href="#" download="aaa.csv" onclick="downloaddata_notie(this)">非IE導出</a>
function downloaddata_notie(aLink) {
var str = "1,2,3,4,5\n9,8,7,5";//demo數據
str = encodeURIComponent(str);//防止亂碼
aLink.href = "data:text/csv;charset=utf-8,\ufeff" + str;
// “\ufeff” 爲 BOM 頭
aLink.click();
return false;
}
感謝您閱讀到這裏。其實寫這篇文章的時候我還沒有將這個功能實現,代碼都是做的demo。
先寫篇文章記錄下來,不然我真的會忘。