法:
COUNT(DISTINCT expr ,[expr ...])
函數(shù)使用說明:返回不同的非NULL 值數(shù)目。若找不到匹配的項,則COUNT(DISTINCT) 返回 0
Mysql的查詢結(jié)果行字段拼接,可以用下面兩個函數(shù)實現(xiàn):
1. concat函數(shù)
mysql> select concat('1','2','3') from test ; +---------------------+ | concat('1','2','3') | +---------------------+ | 123 | +---------------------+
如果連接串中存在NULL,則返回結(jié)果為NULL:
mysql> select concat('1','2',NULL,'3') from test ; +--------------------------+ | concat('1','2',NULL,'3') | +--------------------------+ | NULL | +--------------------------+
2. concat_ws函數(shù)
concat(separator,str1,str2,...) 代表 concat with separator ,是concat()的特殊形式。第一個參數(shù)是其它參數(shù)的分隔符。分隔符的位置放在要連接的兩個字符串之間。分隔符可以是一個字符串,也可以是其它參數(shù)。
mysql> select concat_ws(':','1','2','3') from test ; +----------------------------+ | concat_ws(':','1','2','3') | +----------------------------+ | 1:2:3 | +----------------------------+
分隔符為NULL,則返回結(jié)果為NULL:
mysql> select concat_ws(NULL,'1','2','3') from test; +-----------------------------+ | concat_ws(NULL,'1','2','3') | +-----------------------------+ | NULL | +-----------------------------+
如果參數(shù)中存在NULL,則會被忽略:
mysql> select concat_ws(':','1','2',NULL,NULL,NULL,'3') from test ; +-------------------------------------------+ | concat_ws(':','1','2',NULL,NULL,NULL,'3') | +-------------------------------------------+ | 1:2:3 | +-------------------------------------------+
可以對NULL進行判斷,并用其它值進行替換:
mysql> select concat_ws(':','1','2',ifNULL(NULL,'0'),'3') from bank limit 1; +---------------------------------------------+ | concat_ws(':','1','2',ifNULL(NULL,'0'),'3') | +---------------------------------------------+ | 1:2:0:3 | +---------------------------------------------+
concat的SQL注入:
select username,email,content from test_table where user_id=uid;
上面的user_id是接收輸入的。
concat函數(shù)本來是這樣用的SELECT CONCAT('My', 'S', 'QL');執(zhí)行結(jié)果是'MySQL'。也就是連接作用的。我們利用它來為我們服務(wù),
uid=-1 union select username ,concat(password,sex,address,telephone),content from test_table where user_id=管理員id;
這個語句實際查詢了六個字段,但是顯示的時候,把password,sex,address,telephone等字段合在一起,顯示在原本應(yīng)該顯示email的地方。
感謝閱讀,如果這篇文章幫助了您,歡迎 點贊 ,收藏,關(guān)注,轉(zhuǎn)發(fā) 喲。您的幫助是我們前行的動力,我們會提供更多有價值的內(nèi)容給大家... 謝謝!
格語法:
注意:顏色使用格式有三種:rgb(x,x,x) #xxxxxx colorname
<table width=""></table>指定表格的寬度大小(使用數(shù)字pixel或%)
<table border=""></table>設(shè)定表格邊框大小(使用數(shù)字pixel)
<table align=""></table>表格位置,置左,為默認值
align屬性:left(左對齊表格,默認值)、right(右對齊表格)、center(居中對齊表格)
<table bgcolor=""></table>設(shè)定表格的背景顏色
<table cellpadding=""></table>指定內(nèi)容與網(wǎng)格線之間的間距(使用數(shù)字pixel或%)
<table cellspacing=""></table>指定網(wǎng)格線與網(wǎng)格線之間的距離(使用數(shù)字pixel或%)
<table border="1" cellspacing="0" cellpadding="0">
通常表格, 這兩個參數(shù)都設(shè)置為 0 。
<table rules="rows"></table>規(guī)定內(nèi)側(cè)邊框的哪個部分是可見的。(兼容性差)
rules屬性:none 沒有線條。
groups 位于行組和列組之間的線條。
rows 位于行之間的線條。
cols 位于列之間的線條。
all 位于行和列之間的線條。
<table summary="Monthly savings for the Flintstones family"></table>
定義了表格內(nèi)容的摘要:
表格結(jié)構(gòu):
在使用表格進行布局時, 可以將表格劃分為頭部、主體和頁腳, 具體如下所示:
<thead></thead>:用于定義表格的頭部, 必須位于<table></table>標(biāo)記中, 一般包含網(wǎng)頁的logo和導(dǎo)航等頭部信息。
<tfoot></tfoot>:用于定義表格的頁腳, 位于<table></table>標(biāo)記中<thead></thead>標(biāo)記之后, 一般包含網(wǎng)頁底部的企業(yè)信息等。
<tbody></tbody>:用于定義表格的主體, 位于<table></table>標(biāo)記中<tfoot></tfoot>標(biāo)記之后, 一般包含網(wǎng)頁中除頭部和底部之外的其他內(nèi)容。
注意:在沒有<tbody></tbody>比較的情況下, 瀏覽器會自動添加<tbody></tbody>標(biāo)記。
<table bordercolor=""></table>設(shè)定表格邊框的顏色
<table cols=""></table>指定表格的欄數(shù)
<table height=""></table>指定表格的高度大小(使用數(shù)字)
<table background=""></table>背景圖片的URL=就是路徑網(wǎng)址(默認是repeat:水平和垂直方向重復(fù))
<table bordercolordark=""></table>設(shè)定表格暗邊框的顏色
<table bordercolorlight=""></table>設(shè)定表格亮邊框的顏色
<tr align=""></tr> 定義表格行的內(nèi)容對齊方式。
align屬性值:right、left、center、justify、char
<tr bgcolor=""></tr> 規(guī)定表格行的背景顏色。
<tr valign=""></tr> 規(guī)定表格行中內(nèi)容的垂直對齊方式。
valign屬性值right、left、center、justify、char
<td colspan=""></td>指定儲存格合并欄的欄數(shù)(使用數(shù)字)
<td rowspan=""></td>指定儲存格合并列的列數(shù)(使用數(shù)字)
<td align=""></td> 調(diào)整表格字段之左右對齊
<td bgcolor=""></td> 設(shè)定表格字段之背景顏色
<td colspan="" rowspan=""></td> 表格字段的合并
<td valign=""></td> 調(diào)整表格字段之上下對齊
<td width=""></td> 調(diào)整表格字段寬度
<td nowrap="nowrap"></td> 規(guī)定表格單元格中的內(nèi)容不換行(注意只有一個值:nowrap)
<caption></caption>為表格加上標(biāo)題
<caption align="">設(shè)定表格標(biāo)題位置
align屬性:left, center(默認值), right
<th></th> 定義表頭(粗體居中)
細表格邊框
<table border="1" cellpadding="0" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="158" height="68">
<tr>
<td width="158" height="68"></td>
</tr>
</table>
表格創(chuàng)建后瀏覽器會自動添加<tbody>標(biāo)簽
閱讀本文大概需要 6 分鐘
日常開發(fā)軟件可能會遇到這類小眾需求,導(dǎo)出數(shù)據(jù)到 Word、Excel 以及 PDF文件,如果你使用 C++ 編程語言,那么可以選擇的方案不是很多,恰好最近剛好有這部分需求,整理下這段時間踩過的坑,方便后人
日常開發(fā)的軟件使用最多的應(yīng)該是導(dǎo)出數(shù)據(jù)到 Word 文檔中,目前可以用的方案有這幾種
沒有十全十美的方案,任何方案都存在優(yōu)點和缺點,下面來詳細看下這幾種方案的優(yōu)缺點以及適用場景
“
原理:事先編輯好一份 Word 模板,需要替換內(nèi)容的 地方預(yù)留好位置,然后使用特殊字段進行標(biāo)記,后面使用代碼進行全量替換即可完成
我們先編輯一份 Word 模板文檔,內(nèi)容大概如下所示:
QFile file("XML-Template.xml");
if (!file.open(QIODevice::ReadOnly))
{
qDebug() << "open xxml file fail. " << file.errorString();
return 0;
}
QByteArray baContent=file.readAll();
file.close();
QString strAllContent=QString::fromLocal8Bit(baContent);
strAllContent.replace("$VALUE0", "1");
strAllContent.replace("$VALUE1", QString::fromLocal8Bit("法外狂徒張三"));
strAllContent.replace("$VALUE2", QString::fromLocal8Bit("考試不合格"));
strAllContent.replace("$VALUE3", "2");
strAllContent.replace("$VALUE4", QString::fromLocal8Bit("李四"));
strAllContent.replace("$VALUE5", QString::fromLocal8Bit("合格"));
QFile newFile("export.doc");
if (!newFile.open(QIODevice::WriteOnly))
{
qDebug() << "file open fail." << newFile.errorString();;
return 0;
}
newFile.write(strAllContent.toLocal8Bit());
newFile.close();
可以看出來這種方式比較繁瑣,重點是編輯固定的模板格式,而且編輯好后保存成XML格式后還需要繼續(xù)調(diào)整,這種 XML 格式標(biāo)簽很多,不小心就修改錯了,導(dǎo)致導(dǎo)出的文檔打不開
這種方式適合模板內(nèi)容不太復(fù)雜,內(nèi)容較少的情況下使用
“
原理:采用 Micro Soft公開的接口進行通訊,進行讀寫時會打開一個 `Word進程來交互
COM 技術(shù)概述
Qt 為我們提供了專門進行交互的類和接口,使用 Qt ActiveX框架就可以很好的完成交互工作
使用時需要引入對應(yīng)的模塊,在 pro 文件引入模塊
QT *=axcontainer
打開文檔寫入內(nèi)容
QAxObject *pWordWidget=new(std::nothrow) QAxObject;
bool bResult=pWordWidget->setControl("word.Application");
if (!bResult)
{
return false;
}
// 設(shè)置是否顯示
pWordWidget->setProperty("Visible", false);
QAxObject *pAllDocuments=pWordWidget->querySubObject("Documents");
if(nullptr==pAllDocuments)
{
return false;
}
// 新建一個空白文檔
pAllDocuments->dynamicCall("Add (void)");
// 獲取激活的文檔并使用
QAxObject *pActiveDocument=pAllDocuments->querySubObject("ActiveDocument");
if(nullptr==pActiveDocument)
{
return false;
}
// 插入字符串
QAxObject *pSelectObj=pWordWidget->querySubObject("Selection");
if (nullptr !=pSelectObj)
{
pSelectObj->dynamicCall("TypeText(const QString&)", "公眾號:devstone");
}
……
可以看出來使用起來不難,對于新手友好一點,很多寫入操作方法比較繁瑣,需要自己重新封裝一套接口
這種方式同樣適用于寫入 Excel 文件,后面再說
“
原理:這種方式得益于 Word支持 HTML格式導(dǎo)出渲染顯示,那么反向也可以支持,需要我們拼接 HTML格式內(nèi)容,然后寫入文件保存成 .doc格式
QString HTML2Word::getHtmlContent()
{
QString strHtml="";
strHtml +="<html>";
strHtml +="<head>";
strHtml +="<title>測試生成word文檔</title>";
strHtml +="<head>";
strHtml +="<body style=\"bgcolor:yellow\">";
strHtml +="<h1 style=\"background-color:red\">測試qt實現(xiàn)生成word文檔</h1>";
strHtml +="<hr>";
strHtml +="<p>這里是插入圖片<img src=\"D:\\title.jpg" alt=\"picture\" width=\"100\" height=\"100\"></p>";
strHtml +="</hr>";
strHtml +="</body>";
strHtml +="</html>";
return strHtml;
}
// 保存寫入文件
QFile file("D:/htmp2Word.doc");
if (!file.open(QIODevice::WriteOnly))
{
return false;
}
QTextStream out(&file);
out << getHtmlContent();
file.close();
這種方式難點在于 HTML格式拼接,任何缺失字段都會導(dǎo)致導(dǎo)出失敗,適合小眾需求下導(dǎo)出
圖片問題其實可以手動進行轉(zhuǎn)化,文檔導(dǎo)出成功后手動拷貝內(nèi)容到新的文檔,這樣圖片就真正插入到文檔中,文檔發(fā)送給別人也不會丟失圖片了
還有一個坑就是:如果你使用 WPS 打開導(dǎo)出的文檔,默認顯示的是 web視圖,需要手動進行調(diào)整
某些電腦分辨率變化也會導(dǎo)致生成的文檔中字體等產(chǎn)生變化
可以使用的第三方庫幾乎沒有,網(wǎng)絡(luò)上找到的有這么幾個
DuckX庫 docx庫
在讀寫 Word這部分,C++ 基本沒有可以使用的第三方庫,不像其他語言Java、C#、Python有很多可以選擇,這個痛苦也只有 C++ 程序員能夠理解了吧
所以怎么選擇還是看自己項目需求吧,沒有十全十美的方案
上面說了這么多,都是導(dǎo)出生成 Wrod,那么下面來看看有那些方式可以讀取顯示 Word內(nèi)容
這種需求應(yīng)該不會很多,而且顯示難度更大一些
使用 COM組件方式,即采用 QAxWidget框架顯示 office 文檔內(nèi)容,本質(zhì)上就是在我們編寫的 Qt 界面上嵌入 office 的軟件,這種方式其實和直接打開 Word查看沒有啥區(qū)別,效果、性能上不如直接打開更好一些
目前一般都會采用折中方案,把 Word 轉(zhuǎn)為 PDF 進行預(yù)覽加載顯示,我們知道 PDF 渲染庫比較多,生態(tài)相對來說要好一些,在選擇上就更廣泛些,如何使用后面部分有專門介紹 PDF章節(jié)
目前有一個支持比較好的第三方庫可以使用,整體使用基本可以滿足日常使用
QXlsx
這款開源庫支持跨平臺,Linux、Windows、Mac、IOS、Android,使用方式支持動態(tài)庫調(diào)用和源碼直接集成,非常方便
編譯支持 qmake和cmake,可以根據(jù)你自己的項目直接集成編譯,讀寫速度非常快
QXlsx::Document xlsx;
// 設(shè)置一些樣式
QXlsx::Format titleFormat;
titleFormat.setBorderStyle(QXlsx::Format::BorderThin); // 邊框樣式
titleFormat.setRowHeight(1,1,30); // 設(shè)置行高
titleFormat.setHorizontalAlignment(QXlsx::Format::AlignHCenter); // 設(shè)置對齊方式
// 插入文本
xlsx.write(1,1, "微信公眾號:devstone", titleFormat);
// 合并單元格
xlsx.mergeCells(QXlsx::CellRange(2,1,4,4), titleFormat);
// 導(dǎo)出保存
xlsx.saveAs("D:/xlsx_export.xlsx");
// 添加工作表
xlsx.addSheet("devstone");
可以看到上手非常容易、各個函數(shù)命名也貼近 Qt Api,是一款非常良心的開源軟件
“
PS:注意該軟件使用 MIT 許可協(xié)議,這樣對于很多個人或者公司來說非常良心,意味著你可以無償使用、修改該項目,但是必須在你項目中也添加同樣的 MIP許可
上面也提到了,還可以使用 COM 組件的方式讀寫 Excel,不過有了這款開源庫基本就可以告別 COM組件方式了
PDF相關(guān)開源庫挺多的,給了 C++ 程序員莫大的幫助,目前可用的主要有這些
其中 mupdf和 poppler 屬于功能強大但是很難編譯的那種,需要有扎實的三方庫編譯能力,否則面對 n 個依賴庫會無從下手
不過可喜的是 Github 上有兩個開源庫可以供選擇
這個庫其實封裝了 pdf.js庫,使用 WebEngine來執(zhí)行 JavaScript進而加載文件
項目地址
這種方式對環(huán)境有特殊要求了,如果你的項目使用的 Qt 版本不支持 WebEngine,那么就無法使用
這個庫是 Qt 官方親自操刀對第三方庫進行了封裝,暴露的 API 和 Qt 類似,使用起來非常舒服
Qt 官方
代碼結(jié)構(gòu)以及使用 Demo
關(guān)于如何使用,官方已經(jīng)給了我們非常詳細的步驟了,直接跟著下面幾步就 OK 了
官方教程
git clone git://code.qt.io/qt-labs/qtpdf
cd qtpdf
git submodule update --init --recursive
qmake
make
cd examples/pdf/pdfviewer
qmake
make
./pdfviewer /path/to/my/file.pdf
可以看到使用了谷歌開源的 pdfium 三方庫,編譯時需要單獨更新下載這個庫,因為某些原因可能你無法下載,不過好在有人在 GitHub上同步了這個倉庫的鏡像,有條件還是建議直接下載最新穩(wěn)定版的
可正常訪問的倉庫地址:https://github.com/PDFium/PDFium
相關(guān)類可以看這個文檔:https://developers.foxit.com/resources/pdf-sdk/c_api_reference_pdfium/modules.html
“
最后還要注意項目開源協(xié)議:pdfium引擎開始來自于福昕,一個中國本土的軟件公司,Google與其合作最終進行了開源,目前采用的是 BSD 3-Clause 協(xié)議,這種協(xié)議允許開發(fā)者自由使用、修改源代碼,也可以修改后重新發(fā)布,允許閉源進行商業(yè)行為,不過需要你在發(fā)布的產(chǎn)品中包含原作者代碼中的 BSD 協(xié)議
以上就是項目中常用的文檔處理方法總結(jié),當(dāng)然了肯定也還有其它方案可以實現(xiàn),畢竟條條大路通羅馬,如果你還要不錯的方案和建議歡迎留言
PS: 以上方案和對應(yīng)的源碼編譯、使用例子會統(tǒng)一上傳到 GitHub對應(yīng)的倉庫,方便后人使用
取之互聯(lián)網(wǎng)、回報互聯(lián)網(wǎng)
原創(chuàng)不易,如果覺得對你有幫助,歡迎點贊、在看、轉(zhuǎn)發(fā)
推薦閱讀
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。