|
這個(gè)錯(cuò)誤是由于新版的Swing大量的使用了微軟的DirectDraw的技術(shù)來(lái)提高畫(huà)圖的性能,而可能你的顯卡在這時(shí)候會(huì)跟你鬧點(diǎn)情緒或者顯卡本身并不支持這樣的一個(gè)技術(shù)。難道就沒(méi)有辦法了嘛?要解決這個(gè)問(wèn)題也非常簡(jiǎn)單,我們可以屏蔽掉DirectDraw,不讓Swing使用該技術(shù)就可以了。在運(yùn)行這些代碼時(shí)給虛擬機(jī)指定參數(shù)-Dsun.java2d.noddraw即可。
這時(shí)可能你又該納悶了,不說(shuō)是基于Web的圖表嘛,怎么又扯到Swing上了?這是因?yàn)闉榱耸归_(kāi)發(fā)者容易上手,無(wú)需配置任何運(yùn)行環(huán)境,所以這些例子都是基于GUI方式的用于展現(xiàn)給開(kāi)發(fā)者如果生成一個(gè)圖表,我們要學(xué)習(xí)的也就是如何利用這個(gè)引擎生成圖表而不是怎么來(lái)顯示一個(gè)圖表。當(dāng)我們把生成的圖表對(duì)象Export到一個(gè)圖像文件即可在Web上發(fā)布。
類(lèi)名 |
類(lèi)的作用以及簡(jiǎn)單描述 |
JFreeChart |
圖表對(duì)象,任何類(lèi)型的圖表的最終表現(xiàn)形式都是在該對(duì)象進(jìn)行一些屬性的定制。JFreeChart引擎本身提供了一個(gè)工廠(chǎng)類(lèi)用于創(chuàng)建不同類(lèi)型的圖表對(duì)象 |
XXXXXDataset |
數(shù)據(jù)集對(duì)象,用于提供顯示圖表所用的數(shù)據(jù)。根據(jù)不同類(lèi)型的圖表對(duì)應(yīng)著很多類(lèi)型的數(shù)據(jù)集對(duì)象類(lèi)。常用的數(shù)據(jù)集對(duì)象有:柱狀圖數(shù)據(jù)集對(duì)象DefaultCategoryDataset、餅圖數(shù)據(jù)集對(duì)象DefauldPieDataset和曲線(xiàn)圖數(shù)據(jù)集對(duì)象DefaultTableXYDataset |
XXXXXPlot |
圖表區(qū)域?qū)ο螅旧线@個(gè)對(duì)象決定著什么樣式的圖表,創(chuàng)建該對(duì)象的時(shí)候需要Axis、Renderer以及數(shù)據(jù)集對(duì)象的支持。常用的Plot對(duì)象有:柱狀圖CategoryPlot、餅圖PiePlot和曲線(xiàn)圖XYPlot。 |
XXXXXAxis |
用于處理圖表的兩個(gè)軸:縱軸和橫軸。常用的有NumberAxis數(shù)據(jù)軸,DateAxis日期軸。 |
XXXXXRenderer |
負(fù)責(zé)如何顯示一個(gè)圖表對(duì)象。常用的Renderer有DefaultCategoryItemRenderer 柱狀圖顯示器StandardXYItemRenderer曲線(xiàn)圖顯示器。餅圖的Renderer |
XXXXXURLGenerator |
用于生成Web圖表中每個(gè)項(xiàng)目的鼠標(biāo)點(diǎn)擊鏈接。常用的URLCenerator有StandardCategoryURLGenerator StandardPieURLGenerator StandardXYURLGenerator |
XXXXXToolTipGenerator |
用于生成圖象的幫助提示,不同類(lèi)型圖表對(duì)應(yīng)不同類(lèi)型的工具提示類(lèi)。常用的有:StandardXYToolTipGenerator StandardCategoryToolTipGenerator StandardPieItemLabelGenerator |
一般的創(chuàng)建圖表的過(guò)程為:
1. 從數(shù)據(jù)庫(kù)里讀取數(shù)據(jù)
2. 將數(shù)據(jù)保存到圖表對(duì)應(yīng)的數(shù)據(jù)集對(duì)象中
3. 創(chuàng)建坐標(biāo)軸對(duì)象
4. 創(chuàng)建Renderer對(duì)象
5. 創(chuàng)建Plot對(duì)象
6. 創(chuàng)建JfreeChart對(duì)象
7. 生成圖片文件(或者二進(jìn)制流)
以JfreeChart提供的Web應(yīng)用的例子來(lái)說(shuō)明一下以上幾個(gè)步驟:
一.柱圖。
public static String generateBarChart(Date hitDate, HttpSession session, PrintWriter pw) {
String filename = null;
try {
// Retrieve list of WebHits
WebHitDataSet whDataSet = new WebHitDataSet();
ArrayList list = whDataSet.getDataBySection(hitDate);//獲得數(shù)據(jù)集// Throw a custom NoDataException if there is no data
if (list.size() == 0) {
System.out.println("No data has been found");
throw new NoDataException();
}// Create and populate a CategoryDataset
Iterator iter = list.listIterator();
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
while (iter.hasNext()) {
WebHit wh = (WebHit)iter.next();
dataset.addValue(new Long(wh.getHitCount()), "Hits", wh.getSection());
}//將數(shù)據(jù)集保存到Dataset對(duì)象// Create the chart object
CategoryAxis categoryAxis = new CategoryAxis("");
ValueAxis valueAxis = new NumberAxis("");//創(chuàng)建坐標(biāo)軸
BarRenderer renderer = new BarRenderer();//創(chuàng)建Renderer
renderer.setItemURLGenerator(new StandardCategoryURLGenerator("xy_chart.jsp","series","section"));//創(chuàng)建URLGenerator.再不需要連接的情況下將第一個(gè)參數(shù)設(shè)置成"###"就可以了
renderer.setToolTipGenerator(new StandardCategoryToolTipGenerator());//創(chuàng)建提示標(biāo)簽
Plot plot = new CategoryPlot(dataset, categoryAxis, valueAxis, renderer);//創(chuàng)建圖表區(qū)域?qū)ο?/p>
JFreeChart chart = new JFreeChart("", JFreeChart.DEFAULT_TITLE_FONT, plot, false);
chart.setBackgroundPaint(java.awt.Color.white);//創(chuàng)建圖表
// Write the chart image to the temporary directory
ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());//該工具類(lèi)上面沒(méi)有介紹,在鼠標(biāo)移動(dòng)到圖片時(shí)顯示提示信息是用Map實(shí)現(xiàn)的,這些Map是用該類(lèi)生成的。filename = ServletUtilities.saveChartAsPNG(chart, 500, 300, info, session);//保存圖表為文件
// Write the image map to the PrintWriter
ChartUtilities.writeImageMap(pw, filename, info);//生成Map信息。這些信息寫(xiě)在pw的輸出流中,這里的輸出流就是Response.out。也就是直接輸出到頁(yè)面了pw.flush();
} catch (NoDataException e) {
System.out.println(e.toString());
filename = "public_nodata_500x300.png";
} catch (Exception e) {
System.out.println("Exception - " + e.toString());
e.printStackTrace(System.out);
filename = "public_error_500x300.png";
}
return filename;
}
二.圖表顯示:
<%
......
String filename = WebHitChart.generateBarChart(dDate, session, new PrintWriter(out));//獲得圖片的文件名。注意該語(yǔ)句寫(xiě)在jsp文件(bar_chart.jsp)的開(kāi)頭,而用out的封裝類(lèi)作為參數(shù),訪(fǎng)問(wèn)該頁(yè)面后可以看到生成Map熱點(diǎn)的內(nèi)容輸出再該頁(yè)面的開(kāi)頭部分。也就是說(shuō)最好是把這幾句話(huà)寫(xiě)在頁(yè)面有輸出之前。String graphURL = request.getContextPath() + "/servlet/DisplayChart?filename=" + filename;//顯示圖片的Servlet全路徑名,另外文件名作為該Servlet的參數(shù)
......
%>
......
<img src="<%= graphURL %>" width=500 height=300 border=0 usemap="#<%= filename %>">
src指定了servlet的全路徑名,usermap指定了使用的熱點(diǎn)。
該Servlet必須在WEB-INF/web.xml文件中配置:
<servlet>
<servlet-name>DisplayChart</servlet-name>
<servlet-class>org.jfree.chart.servlet.DisplayChart</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DisplayChart</servlet-name>
<url-pattern>/servlet/DisplayChart</url-pattern>
</servlet-mapping>
該Servlet的作用就是將圖片文件的二進(jìn)制流數(shù)據(jù)寫(xiě)道response的輸出流中,在客戶(hù)端也就顯示成了圖片。
博客中國(guó)分類(lèi):java技術(shù),
jfreechart是一個(gè)優(yōu)秀的開(kāi)源JAVA 2D項(xiàng)目,缺點(diǎn)是缺乏文檔,中英文都是如此。本文是經(jīng)驗(yàn)總結(jié)的第二部分
二、jfreechart作圖類(lèi)對(duì)象的協(xié)調(diào)關(guān)系
jfreechart 的繪圖對(duì)象由一個(gè)org.jfree.chart.JFreeChart組成,但作為繪圖關(guān)鍵的Graphich2d通過(guò) org.jfree.chart.render.*中的對(duì)應(yīng)render類(lèi)包裝后設(shè)入,換言之,開(kāi)發(fā)者可以通過(guò)對(duì)基礎(chǔ)圖板Graphic的設(shè)置,完成必要的繪圖預(yù)定效果設(shè)計(jì);而大多數(shù)的修改,實(shí)際上可以通過(guò)包裝的各個(gè)類(lèi)操作而不用直接修改Graphic對(duì)象屬性(誰(shuí)記得呢?)。jfreechart的數(shù)據(jù)接口由org.jfree.chart.plot.*中的不同的plot包裝,與之相對(duì)應(yīng)的是不同的dataset,位于 org.jfree.chart.data.*中不同的dataset接口包裝。使用jfreechart作圖的關(guān)鍵在于生一個(gè)個(gè)相應(yīng)的數(shù)據(jù)集對(duì)象,,然后包裝成對(duì)應(yīng)的一個(gè)個(gè)繪圖集plot對(duì)象,最后再包裝成不同的JFreeChart對(duì)象交付輸出。通過(guò)new方法可以一步步完成上面的步驟。換言之, plot類(lèi)是圖形的設(shè)計(jì),render 是繪制的工具,而dataset則是填充的數(shù)據(jù);這樣就把作圖的三個(gè)關(guān)鍵因素分別抽象成統(tǒng)一的接口,互想搭配出各種圖形。對(duì)于可能有多套數(shù)據(jù)集的圖表,如時(shí)間序列的多條曲線(xiàn)走勢(shì)圖(象幾只股票),傳入plot的不是數(shù)據(jù)集,而是數(shù)據(jù)集的集合,一般命名為某某collection。
通過(guò) ChartFactory的不同方法生成不同的Chart類(lèi)型,可以相應(yīng)地縮小了由dataset對(duì)不同的chart對(duì)象的操作過(guò)程代碼量,直接獲得 chart對(duì)象。實(shí)際上是由工廠(chǎng)類(lèi)代替用戶(hù)生成必要的render和plot類(lèi),如果用戶(hù)不想使用默認(rèn)的設(shè)置,就需要再通過(guò)get方法得出相應(yīng)的plot 對(duì)象進(jìn)行修改。jfreechart的最后圖像輸出一般由org.jfree.chart.ChartUtilites完成,這個(gè)類(lèi)可以向接定的 PrintWriter對(duì)象輸出完成的Chart對(duì)象。在服務(wù)器程序中,另一個(gè)ServerUtilites方法調(diào)用了這個(gè)方法,生成一個(gè)圖像臨時(shí)文件,并向JSP或servlet返回這個(gè)文件對(duì)象,通過(guò)把這個(gè)圖像的生命周期與session綁定,希望可以實(shí)現(xiàn)緩沖功能,降低服務(wù)器動(dòng)態(tài)生成圖像的損耗。但是也有很大的問(wèn)題其一就是如果session很長(zhǎng),就等于不能生成實(shí)時(shí)圖像,其二就是訪(fǎng)問(wèn)的人多了,服務(wù)器的負(fù)擔(dān)似乎反而加大了。這個(gè)算法顯然有問(wèn)題,倒不如修改成按時(shí)間更新一個(gè)圖像更為合適。
觀(guān)察代碼,兩者效果是一樣的:
A、工廠(chǎng)方法:
JFreeChart chart = ChartFactory.createPieChart3D( "2000 GDP分布比例圖", data, true, false, false );//指定獲得不同的實(shí)現(xiàn)chart對(duì)象,含有不同的plot繪圖對(duì)象
PiePlot plot = (PiePlot) chart.getPlot();//獲取plot對(duì)象用于修訂屬性,強(qiáng)制造型,以便調(diào)用各自的方法
plot.setLabelGenerator(new StandardPieItemLabelGenerator( "{0} = {2}", NumberFormat.getNumberInstance(), NumberFormat.getPercentInstance() ));//設(shè)定注釋方式
plot.setForegroundAlpha(0.5f);//設(shè)定透明度
plot.setNoDataMessage("無(wú)記錄內(nèi)容");//無(wú)記錄異常顯示
B、手工生成對(duì)象
PiePlot plot = new PiePlot(dataset);
plot.setLabelGenerator(new StandardPieItemLabelGenerator( "{0} = {2}", NumberFormat.getNumberInstance(), NumberFormat.getPercentInstance() ));//設(shè)定注釋方式
plot.setForegroundAlpha(0.5f);//設(shè)定透明度
plot.setNoDataMessage("無(wú)記錄內(nèi)容");//無(wú)記錄異常顯示
JFreeChart chart = new JFreeChart("", JFreeChart.DEFAULT_TITLE_FONT, plot, false);
一:jfreechart介紹jfreechart是一個(gè)免費(fèi)創(chuàng)建圖片的java工具.可以創(chuàng)建如下圖形:
餅圖(pie charts;)
曲線(xiàn)圖(line charts )
柱狀圖(horizontal/vertical bar charts)
甘特圖(Gantt charts; )
XY plots and scatter plots;
time series, high/low/open/close charts and candle stick charts;
combination charts;
Pareto charts;
bubble charts;
wind plots, meter charts and symbol charts;
從以下地址可以看到j(luò)freechart可以創(chuàng)建的圖形類(lèi)型
http://www.jfree.org/jfreechart/samples.html
sourceforge有一個(gè)基于jfreechart的項(xiàng)目Cewolf可以很方便的在jsp/servlet中創(chuàng)建圖片
jfreechart目前(2003-05-08)版本為0.98
希望得到詳細(xì)的信息或下載jfreechart請(qǐng)?jiān)L問(wèn)如下站點(diǎn):
http://www.jfree.org/jfreechart/
二:特別說(shuō)明:
jfreechart是一個(gè)開(kāi)源項(xiàng)目,但是文檔是需要40美金去購(gòu)買(mǎi)的。
還有一個(gè)很重要的問(wèn)題,jfreechart如果使用中文,他使用的默認(rèn)字體
顯示出來(lái)的中文會(huì)很模糊,你可能需要修改源代碼。
下面我就舉幾個(gè)簡(jiǎn)單的例子說(shuō)明一下如何使用jfreechart創(chuàng)建圖片
在開(kāi)發(fā)中有可能會(huì)導(dǎo)入以下的類(lèi)
import com.jrefinery.chart.ChartFactory;
import com.jrefinery.chart.ChartUtilities;
import com.jrefinery.chart.JFreeChart;
import com.jrefinery.chart.TextTitle;
import com.jrefinery.chart.axis.NumberAxis;
import com.jrefinery.chart.plot.CategoryPlot;
import com.jrefinery.chart.plot.PiePlot;
import com.jrefinery.data.Day;
import com.jrefinery.data.DefaultCategoryDataset;
import com.jrefinery.data.DefaultPieDataset;
import com.jrefinery.data.TimeSeries;
import com.jrefinery.data.TimeSeriesCollection;
import com.jrefinery.data.TimeSeriesDataPair;
在0.98以后包由com.jrefinery.*改變?yōu)?org.jfree
三:創(chuàng)建餅圖
//圖片標(biāo)題
String title = "空調(diào)2002年市場(chǎng)占有率";
//設(shè)定數(shù)據(jù)源
DefaultPieDataset piedata = new DefaultPieDataset();
//第一個(gè)參數(shù)為名稱(chēng),第二個(gè)參數(shù)是double數(shù)
piedata.setValue("聯(lián)想", 27.3);
piedata.setValue("長(zhǎng)城", 12.2);
piedata.setValue("海爾", 5.5);
piedata.setValue("美的", 17.1);
piedata.setValue("松下", 9.0);
piedata.setValue("科龍", 19.0);
//創(chuàng)建JFreeChart,都使用ChartFactory來(lái)創(chuàng)建JFreeChart,很標(biāo)準(zhǔn)的工廠(chǎng)設(shè)計(jì)模式
JFreeChart chart =
ChartFactory.createPieChart(title, piedata, true, true, true);
//設(shè)定圖片標(biāo)題
chart.setTitle(new TextTitle(title, new Font("隸書(shū)", Font.ITALIC, 15)));
//chart.addSubtitle(new TextTitle("2002財(cái)年分析", new Font("隸書(shū)", Font.ITALIC, 12)));
//設(shè)定背景
chart.setBackgroundPaint(Color.white);
//chart.s
//餅圖使用一個(gè)PiePlot
PiePlot pie = (PiePlot)chart.getPlot();
//pie.setSectionLabelType(PiePlot.NAME_AND_PERCENT_LABELS);
pie.setSectionLabelType(PiePlot.NAME_AND_VALUE_LABELS);
//設(shè)定顯示格式(名稱(chēng)加百分比或數(shù)值)
pie.setPercentFormatString("#,###0.0#%");
//設(shè)定百分比顯示格式
pie.setBackgroundPaint(Color.white);
pie.setSectionLabelFont(new Font("黑體", Font.TRUETYPE_FONT, 12));
//設(shè)定背景透明度(0-1.0之間)
pie.setBackgroundAlpha(0.6f);
//設(shè)定前景透明度(0-1.0之間)
pie.setForegroundAlpha(0.90f);
//輸出文件到指定目錄
String rfname = MathUtil.getRoundCode(12) + ".jpeg";
String fileName = "d:/test/" + rfname;
try {
//可以保存文件為jpg或png格式。
ChartUtilities.saveChartAsJPEG(new File(fileName), 100, chart, 600, 600);
//第一個(gè)參數(shù)為文件名
//第二個(gè)參數(shù)質(zhì)量
//第三個(gè)參數(shù)為哪個(gè)chart創(chuàng)建圖片
//第四個(gè)寬度
//第五個(gè)高度
} catch (IOException exz) {
System.out.print("....Cant't Create image File");
}
其實(shí)使用JFreeChart創(chuàng)建圖片很簡(jiǎn)單,不同的的圖片類(lèi)型區(qū)別在于設(shè)置數(shù)據(jù)集
四:創(chuàng)建曲線(xiàn)圖
// create a default chart based on some sample data...
//曲線(xiàn)圖標(biāo)題
String title = "趨勢(shì)分析";
//曲線(xiàn)圖X軸提示
String domain = "月份走勢(shì)";
//曲線(xiàn)圖Y軸提示
String range = "應(yīng)收余額";
//曲線(xiàn)圖自標(biāo)題
String subtitleStr = "2003財(cái)年分析";
//創(chuàng)建時(shí)間數(shù)據(jù)源
//每一個(gè)TimeSeries在圖上是一條曲線(xiàn)
TimeSeries ca = new TimeSeries("用友");
for (int i = 1999; i < 2005; i++) {
for (int mon = 0; mon < 12; mon++) {
//ca.add(new Month(mon + 1, i), new Double(500 + Math.random() * 100));
//TimeSeriesDataPair是一個(gè)時(shí)間點(diǎn)的數(shù)值體現(xiàn)
ca.add(
new TimeSeriesDataPair(
new Day(1, mon + 1, i),
new Double(500 + Math.random() * 100)));
}
}
TimeSeries ibm = new TimeSeries("金碟");
for (int i = 1999; i < 2005; i++) {
for (int mon = 0; mon < 12; mon++) {
//ibm.add(new Month(mon+1,i),new Double(400-Math.random()*100));
ibm.add(
new TimeSeriesDataPair(
new Day(1, mon + 1, i),
new Double(400 - Math.random() * 100)));
}
}
TimeSeries king = new TimeSeries("東軟");
for (int i = 1999; i < 2005; i++) {
for (int mon = 0; mon < 12; mon++) {
//ibm.add(new Month(mon+1,i),new Double(400-Math.random()*100));
king.add(
new TimeSeriesDataPair(
new Day(1, mon + 1, i),
new Double(300 - Math.random() * 100)));
}
}
//時(shí)間曲線(xiàn)數(shù)據(jù)集合
TimeSeriesCollection dataset = new TimeSeriesCollection();
dataset.addSeries(ca);
dataset.addSeries(ibm);
dataset.addSeries(king);
//dataset.addSeries(jpy);
//dataset.addSeries(mav);
//時(shí)間曲線(xiàn)元素
JFreeChart chart =
ChartFactory.createTimeSeriesChart(
title,
domain,
range,
dataset,
true,
true,
false);
// then customise it a little...
TextTitle subtitle =
new TextTitle(subtitleStr, new Font("黑體", Font.BOLD, 12));
chart.addSubtitle(subtitle);
chart.setTitle(new TextTitle(title, new Font("隸書(shū)", Font.ITALIC, 15)));
//pie.setSeriesLabelFont(new Font("黑體", Font.BOLD, 15));
chart.setBackgroundPaint(
new GradientPaint(0, 0, Color.white, 0, 1000, Color.blue));
//sysout
//輸出文件到指定目錄
String rfname = MathUtil.getRoundCode(22) + ".jpeg";
String fileName = "d:/test/" + rfname;
try {
//for
//System.out.println();
ChartUtilities.saveChartAsJPEG(new File(fileName), 100, chart, 600, 600);
// log.info("....Create image File:" + fileName);
} catch (IOException exz) {
System.out.print("....Cant't Create image File");
}
五:創(chuàng)建柱狀圖
String title = "柱狀圖測(cè)試";
String domain = "單位比較";
String range = "數(shù)值";
//CategoryDataset data = DemoDatasetFactory.createCategoryDataset();
DefaultCategoryDataset data = new DefaultCategoryDataset();
for (int r = 0; r < 5; r++) {
String rowKey = "單位 [" + (r + 1)+"]" ;
//第一層循環(huán):分析對(duì)象
for (int c = 0; c < 6; c++) {
//第二層循環(huán):分析對(duì)象在時(shí)間點(diǎn)上的數(shù)據(jù)
String columnKey = "2001年" + (c + 1) + "月";
data.addValue(new Double(r * c + 5), rowKey, columnKey);
}
}
JFreeChart chart =
ChartFactory.createVerticalBarChart(
title,
domain,
range,
data,
true,
true,
false);
// then customise it a little...
chart.setBackgroundPaint(
new GradientPaint(0, 0, Color.white, 1000, 0, Color.red));
chart.setTitle(new TextTitle(title, new Font("隸書(shū)", Font.ITALIC, 15)));
CategoryPlot plot = (CategoryPlot)chart.getPlot();
plot.setForegroundAlpha(0.9f);
plot.setValueLabelFont(new Font("黑體", Font.TRUETYPE_FONT, 12));
//plot.setSectionLabelFont(new Font("黑體", Font.TRUETYPE_FONT, 12));
//注意以下代碼
NumberAxis verticalAxis = (NumberAxis)plot.getRangeAxis();
verticalAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
// 輸出文件到指定目錄
String rfname = MathUtil.getRoundCode(22) + "b.jpeg";
String fileName = "d:/test/" + rfname;
try {
ChartUtilities.saveChartAsJPEG(new File(fileName), 100, chart, 600, 600);
// log.info("....Create image File:" + fileName);
} catch (IOException exz) {
System.out.print("....Cant't Create image File");
}
六:結(jié)束語(yǔ)
個(gè)人感覺(jué)JFreeChart可以滿(mǎn)足大部分圖片創(chuàng)建的需要,美中不足的是:對(duì)字體的設(shè)置做的
不夠好,特別是使用中文的時(shí)候字體很不清晰。因?yàn)檫@個(gè)原因建議你自己去修改他的源代碼,最好使用properties文件去設(shè)置字體.還有就是文檔要錢(qián)所以要多花點(diǎn)時(shí)間去看源代碼。或多上社區(qū).因?yàn)闀r(shí)間等原因我只介紹了三種圖片的創(chuàng)建,其他類(lèi)型的圖片可以參考jfreechart提供的例子。
凡是有該標(biāo)志的文章,都是該blog博主Caoer(草兒)原創(chuàng),凡是索引、收藏
、轉(zhuǎn)載請(qǐng)注明來(lái)處和原文作者。非常感謝。