posts - 120,  comments - 19,  trackbacks - 0

自己最近学习了JfreeChart的使用,觉得这个冬冬的功能非常强大,总结一下。
一、简单介绍一下
    WW
的发展使得基于因特网的应用程序不再局限于静态或者简单的动态内容提供。传统的一些以软件包形式发布应用程序例如报表系统等都在逐渐搬到因特网上。但是这两者之间有着天壤之别,虽然对于数据获取、业务处理等方面基本类似,但是最大的差别在于用户界面。为了能在web浏览器上显示要求用户界面使用 HTML以及图片的方式来展现数据,而传统的一些利用操作系统本身的控件来开发的用户界面无法适应琳琅满目的客户端,因此在这里也变得无能为力。回到本文的题目上来,为了创建一个可以在web浏览器上查看到图表一般有两种做法:第一种就是使用applet利用java本身对图形的支持来显示一个图表;第二 种就是直接在web服务器端生成好图表图片文件后发送给浏览器。第一种方式显然对于客户端要求太高,随着现在主流浏览器放弃对JAVA的支持后,这种方式 只适合一些局域网的应用,而对于因特网的环境就显得不太适合。因此我们下面将介绍一个JAVA的图表引擎JFreeChart用来产生基于WEB的图表。
    JFreeChart
项目简介 JFreeChart是开放源代码站点SourceForge.net上的一个JAVA项目,它主要用来各种各样的图表,这些图表包括:饼图、柱状图(普 通柱状图以及堆栈柱状图)、线图、区域图、分布图、混合图、甘特图以及一些仪表盘等等。这些不同式样的图表基本上可以满足目前的要求。

二、JFreeChart获取。
         JFreeChart JFreeChart公司在开源网站SourceForge.net上的一个项目,该公司的主要产品有如下:
         1.JFreeReport :报表解决工具
         2.JFreeChart:Java 图形解决方案Application/Applet/Servlet/Jsp
         3.JCommon JFreeReportJFreeChart的公共类库
         4.JFreeDesigner JFreeReport的报表设计工具
     我们可以从jfree官方网站上获取最新版本和相关资料(但是jfreedocument需要40美金才能获取),
     获取地址:http://www.jfree.org/jfreechart/index.html(同时可以获得简明介绍)
     我们以当前最新版本:jfreechart-1.0.1.zip为例子进行说明。

三、JFreeChart配置安装
     1 、解压jfreechart-1.0.1.zip.zip到指定位置,其中sourcejfreechart的源码,jfreechart-1.0.1-demo.jar   是例子程序,可以先运行一下看看各种效果,就知道他的nb之处了。
    2
、为了配置成功,我们需要关注的文件有如下三个:
    设置classpath。加入下面三个jar包。
    jfreechart-1.0.1.jar
jcommon-1.0.0.jargnujaxp.jar
    加上第三个jar包有时web.xml会报错,把它去掉就好了。
        至此jfreechart的配置就完成了,下面就可以进行jfreechart的开发了。这里值得提出的是jfreechart的类
        结构设计前后兼容性不是很好,不同版本的jfreechart中类库结构可能不一样,有时候可能需要查源码。如果是中文显示的时候可能依据观感需要改变源码的字体。


四、JFreeChart功能介绍
     JFreeChart 目前是最好的java图形解决方案,基本能够解决目前的图形方面的需求,主要包括如下几个方面:
     pie   charts   (2D   and   3D) :饼图(平面和立体)
     bar   charts   (regular   and   stacked,   with   an   optional   3D   effect) :柱状图
     line   and   area   charts :曲线图
     scatter   plots   and   bubble   charts
     time   series,   high/low/open/close   charts   and   candle   stick   charts :时序图
     combination   charts :复合图
     Pareto   charts
     Gantt   charts :甘特图
     wind   plots,   meter   charts   and   symbol   charts
     wafer   map   charts
     ( 态图表,饼图(二维和三维)   ,   柱状图   ( 水平,垂直),线图,点图,时间变化图,甘特图,   股票行情图,混和图,   温度计图,   刻度图等常用商用图表)
     图形可以导出成PNGJPEG格式,同时还可以与PDFEXCEL关联
     JFreeChart 核心类库介绍:
             研究jfreechart源码发现源码的主要由两个大的包组成:org.jfree.chart,org.jfree.data。其中前者主要与图形
     本身有关,后者与图形显示的数据有关。具体研究如果大家有兴趣的话可以自己研究   
          核心类主要有:
            org.jfree.chart.JFreeChart :图表对象,任何类型的图表的最终表现形式都是在该对象进行一些属性的定制。JFreeChart引擎本身提供了一个工厂类用于创建不同类型的图表对象
            org.jfree.data.category.XXXDataSet: 数据集对象,用于提供显示图表所用的数据。根据不同类型的图表对应着很多类型的数据集对象类
            org.jfree.chart.plot.XXXPlot :图表区域对象,基本上这个对象决定着什么样式的图表,创建该对象的时候需要AxisRenderer以及数据集对象的支持
            org.jfree.chart.axis.XXXAxis :用于处理图表的两个轴:纵轴和横轴
            org.jfree.chart.render.XXXRender :负责如何显示一个图表对象
            org.jfree.chart.urls.XXXURLGenerator: 用于生成Web图表中每个项目的鼠标点击链接
            XXXXXToolTipGenerator: 用于生成图象的帮助提示,不同类型图表对应不同类型的工具提示类

    个人感觉JFreeChart可以满足大部分图片创建的需要,美中不足的是:对字体的设置做的不够好,特别是使用中文的时候字体很不清晰。因为这个原因建议你自己去修改他的源代码
最好使用properties文件去设置字体.还有就是文档要钱所以要多花点时间去看源代码。或多上社区.

五.开始开发
    对JfreeChart有了初步了解并做好准备工作之后,开始作例子程序试验。在这里我只介绍饼图的做法,而这张图采用不同的方式进行输出,其他类型的图片可以参考jfreechart提供的例子,做法都差不多。

1) 直接生成图片
package com.jfreechart.picture.example;
import java.awt.Color;
import java.awt.Font;
import java.io.FileOutputStream;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.PiePlot3D;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;

/**

* 该类用于演示饼图生成,生成图片

*/
public class PieChartPicture {

public static void main(String[] args)

    {
      PieDataset dataset = getDataSet();
      JFreeChart chart = ChartFactory.createPieChart3D(
       "
项目进度分布",  // chart title
          
dataset,             // data
            true,               // include legend
            true,
            false
            );
    PiePlot3D  plot=(PiePlot3D)chart.getPlot();
    //
图片中显示百分比:默认方式
    //plot.setLabelGenerator(new           StandardPieSectionLabelGenerator(StandardPieToolTipGenerator.DEFAULT_TOOLTIP_FORMAT));
// 图片中显示百分比:自定义方式,{0} 表示选项, {1} 表示数值, {2} 表示所占比例 ,小数点后两位
    plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0}={1}({2})", NumberFormat.getNumberInstance(), new DecimalFormat("0.00%")));

// 图例显示百分比:自定义方式, {0} 表示选项, {1} 表示数值, {2} 表示所占比例                 plot.setLegendLabelGenerator(new StandardPieSectionLabelGenerator("{0}={1}({2})"));

// 设置背景色为白色

       chart.setBackgroundPaint(Color.white);

       // 指定图片的透明度(0.0-1.0)

        plot.setForegroundAlpha(1.0f);

        // 指定显示的饼图上圆形(false)还椭圆形(true)

        plot.setCircular(true);

        // 设置图标题的字体

       Font font = new Font(" 黑体",Font.CENTER_BASELINE,20);

       TextTitle title = new TextTitle(" 项目状态分布");

       title.setFont(font); 

       chart.setTitle(title);

       FileOutputStream fos_jpg = null;

        try {

           fos_jpg=new FileOutputStream("D:\\ 项目状态分布.jpg");

           ChartUtilities.writeChartAsJPEG(fos_jpg,100,chart,640,480,null);

           fos_jpg.close();

       } catch (Exception e) {

           // TODO: handle exception

       }

 }

 private static PieDataset getDataSet() {

             DefaultPieDataset dataset = new DefaultPieDataset();

            dataset.setValue(" 市场前期", new Double(10));

            dataset.setValue(" 立项", new Double(15));

            dataset.setValue(" 计划", new Double(10));

            dataset.setValue(" 需求与设计", new Double(10));

            dataset.setValue(" 执行控制", new Double(35));

            dataset.setValue(" 收尾", new Double(10));

            dataset.setValue(" 运维",new Double(10));

            return dataset;       

        }
}

2) 采用servletstrutsaction方式输出

采用这种方式输出,不用生成图片。

A servlet输出

package com.jfreechart.servlet.example;

import java.io.IOException;

import java.awt.Color;

import java.awt.Font;

import java.text.NumberFormat;

import java.text.DecimalFormat;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.HttpServlet;

import org.jfree.chart.title.TextTitle;

import org.jfree.chart.ChartFactory;

import org.jfree.chart.ChartUtilities;

import org.jfree.chart.JFreeChart;

import org.jfree.data.general.DefaultPieDataset;

import org.jfree.data.general.PieDataset;

import org.jfree.chart.plot.*;

import org.jfree.chart.labels.StandardPieSectionLabelGenerator;

/**

* 演示通过servlet直接输出饼图

*/

public class PieByServlet extends HttpServlet{

public void service(ServletRequest req, ServletResponse res)

    throws ServletException, IOException

    {

       res.setContentType("image/jpeg");

       PieDataset dataset = getDataSet();

       JFreeChart chart = ChartFactory.createPieChart3D(

                " 水果饼图",  // chart title

                dataset,             // data

                true,               // include legend

                true,

                false

            );

       PiePlot3D  plot=(PiePlot3D)chart.getPlot(); 

       // 图片中显示百分比:默认方式

       //plot.setLabelGenerator(new StandardPieSectionLabelGenerator(StandardPieToolTipGenerator.DEFAULT_TOOLTIP_FORMAT));

// 图片中显示百分比:自定义方式,{0} 表示选项, {1} 表示数值, {2} 表示所占比例 ,小数点后两位

     plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0}={1}({2})", NumberFormat.getNumberInstance(), new DecimalFormat("0.00%")));

// 图例显示百分比:自定义方式, {0} 表示选项, {1} 表示数值, {2} 表示所占比例

      plot.setLegendLabelGenerator(new StandardPieSectionLabelGenerator("{0}={1}({2})"));

 // 设置背景色为白色

       chart.setBackgroundPaint(Color.white);

       // 指定图片的透明度(0.0-1.0)

        plot.setForegroundAlpha(1.0f);

        // 指定显示的饼图上圆形(false)还椭圆形(true)

        plot.setCircular(true);

        // 设置图标题的字体

       Font font = new Font(" 黑体",Font.CENTER_BASELINE,20);

       TextTitle title = new TextTitle(" 项目状态分布");

       title.setFont(font);

        chart.setTitle(title);

       // 输出图片

       ChartUtilities.writeChartAsJPEG(res.getOutputStream(),100,chart,800,600,null);

    }

    /**

    * 获取一个演示用的简单数据集对象

    * @return

    */

    private static DefaultPieDataset getDataSet() {

       DefaultPieDataset dataset = new DefaultPieDataset();

            dataset.setValue(" 市场前期", new Double(10));

            dataset.setValue(" 立项", new Double(15));

            dataset.setValue(" 计划", new Double(10));

            dataset.setValue(" 需求与设计", new Double(10));

            dataset.setValue(" 执行控制", new Double(35));

            dataset.setValue(" 收尾", new Double(10));

            dataset.setValue(" 运维",new Double(10));

            return dataset;       
    }
}

B strutsaction方式输出

只将这条语句加上try catch即可,并返回null

try{       ChartUtilities.writeChartAsJPEG(response.getOutputStream(),100,chart,800,600,null);

    } catch (Exception e) {

              // TODO: handle exception

    }
return null;

其实采用这两种方式与生成图片的方式改动并不大

加上语句response.setContentType("image/jpeg");

ChartUtilities.writeChartAsJPEG(new FileOutputStream("D:\\ 项目状态分布.jpg");,100,chart,640,480,null);

文件流改成response的输出流就可以了

ChartUtilities.writeChartAsJPEG(response.getOutputStream(),100,chart,800,600,null);

 

 3)jspservletjavabean方式

1. Create ChartViewer servlet (ChartViewer.java)

Code:

/**

 * Need to produce some chart prior to this action call in a Java bean

 * Need a session attribute named "chartImage";

 */

package myapp.webwork.servlets;

import java.io.*;

import java.awt.image.*;

import javax.servlet.*;

import javax.servlet.http.*;

import com.keypoint.PngEncoder;

public class ChartViewer extends HttpServlet {

 public void init() throws ServletException {

  }

 
//Process the HTTP Get request

  public void doGet(HttpServletRequest request, HttpServletResponse response)

         throws ServletException, IOException {

  // get the chart from session

   HttpSession session = request.getSession();

   BufferedImage chartImage = (BufferedImage) session.getAttribute("chartImage");

// set the content type so the browser can see this as a picture

   response.setContentType("image/png");

// send the picture

   PngEncoder encoder = new PngEncoder(chartImage, false, 0, 9);

   response.getOutputStream().write(encoder.pngEncode());

}

//Process the HTTP Post request

  public void doPost(HttpServletRequest request, HttpServletResponse response)

         throws ServletException, IOException {

    doGet(request, response);

  }

//Process the HTTP Put request

  public void doPut(HttpServletRequest request, HttpServletResponse response)

         throws ServletException, IOException {

  }

//Clean up resources

  public void destroy() {

  }

}

 
2. Compile and store the servlet under WEB-INF/classes

<appname>WEB-INF/classes/myapp/webwork/servlets

3. Create a servlet map in web.xml

Code:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE web-app

    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"

    "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">

<web-app>

  <servlet>

    <servlet-name>ChartViewer</servlet-name>

    <servlet-class>myapp.webwork.servlets.ChartViewer</servlet-class>

  </servlet>

  <servlet-mapping>

    <servlet-name>ChartViewer</servlet-name>

    <url-pattern>/servlet/ChartViewer</url-pattern>

  </servlet-mapping>

</web-app>

4. Create a chart in a java bean (Pie3DDemo.java)

Code:

/**

 *

 * JFreeChart version 0.9.20

 * Called by Pie3DDemo.jsp

 *

 */

package myapp.webwork.beans;

import java.io.*;

import java.awt.*;

import java.util.*;

import java.awt.image.*;

import org.jfree.data.*;

import org.jfree.chart.*;

import org.jfree.chart.plot.*;

import org.jfree.chart.urls.*;

import org.jfree.chart.entity.*;

import javax.servlet.http.*;

public class Pie3DDemo {

 public Pie3DDemo() {

  }

private DefaultPieDataset getDataset() {

    // categories...

    String[] section = new String[] {

      "Jan","Feb","Mar","Apr","May","Jun",

      "Jul","Aug","Sep","Oct","Nov","Dec"

   };

 // data...

    double[] data = new double[section.length];

    for (int i = 0; i < data.length; i++) {

        data[i] = 10 + (Math.random() * 10);

    }

// create the dataset...

    DefaultPieDataset dataset = new DefaultPieDataset();

    for (int i = 0; i < data.length; i++) {

        dataset.setValue(section[i], data[i]);

    }

    return dataset;

  }

 public String getChartViewer(HttpServletRequest request, HttpServletResponse response) {

    DefaultPieDataset dataset = getDataset();

    // create the chart...

    JFreeChart chart = ChartFactory.createPie3DChart(

          "Pie3D Chart Demo",  // chart title

          dataset,             // data

          true,                // include legend

          true,

          false

    );

  // set the background color for the chart...

    chart.setBackgroundPaint(Color.cyan);

    PiePlot plot = (PiePlot) chart.getPlot();

    plot.setNoDataMessage("No data available");

 // set drilldown capability...

    plot.setURLGenerator(new StandardPieURLGenerator("Bar3DDemo.jsp","section"));

    plot.setLabelGenerator(null);

  // OPTIONAL CUSTOMISATION COMPLETED.

  ChartRenderingInfo info = null;

    HttpSession session = request.getSession();

    try {

  //Create RenderingInfo object

      response.setContentType("text/html");

      info = new ChartRenderingInfo(new StandardEntityCollection());

      BufferedImage chartImage = chart.createBufferedImage(640, 400, info);

  // putting chart as BufferedImage in session,

      // thus making it available for the image reading action Action.

      session.setAttribute("chartImage", chartImage);

     PrintWriter writer = new PrintWriter(response.getWriter());

      ChartUtilities.writeImageMap(writer, "imageMap", info);

      writer.flush();

  }

    catch (Exception e) {

       // handel your exception here

    }

 String pathInfo = "http://";

    pathInfo += request.getServerName();

    int port = request.getServerPort();

    pathInfo += ":"+String.valueOf(port);

    pathInfo += request.getContextPath();

    String chartViewer = pathInfo + "/servlet/ChartViewer";

    return chartViewer;

  }

}

 

5. Compile and store the bean under WEB-INF/classes

<appname>WEB-INF/classes/myapp/webwork/beans

6. Create Pie3DDemo.jsp code

Code:

<html>

<head>

<title>Pie Chart Demo</title>

</head>

<jsp:useBeanid="myChart"scope="session"class="myapp.webwork.beans.Pie3DDemo" />

<body>

<h2>Pie Chart Demo</h2>

<%String chartViewer = myChart.getChartViewer(request, response);%>

<img src="<%=chartViewer%>" border=0 usemap="#imageMap">

</body>

</html>

 4)采用工具类,DisplayChart输出
我用了上面的几个方法输出图片,发现页面里只能输出一个图片
不过下面的方法可以输出多个图片

1 .添加工具类ChartUtil

public class ChartUtil {

//  产生时间序列图,返回图片名称

     // 产生饼图,返回图片名称

      public  static String generatePieChart(DefaultPieDataset dataset,String title,int width,int height,HttpSession session, PrintWriter pw) {

           String filename = null;

           try {

              if (session != null)

              {

                  ChartDeleter deleter = (ChartDeleter)session.getAttribute("JFreeChart_Deleter");

                  session.removeAttribute("JFreeChart_Deleter");

                  session.setAttribute("JFreeChart_Deleter", deleter);

              }

               JFreeChart chart = ChartFactory.createPieChart3D(

                        title,  // chart title

                        dataset,             // data

                        true,                // include legend

                        true,

                        false

                  );

    //  Write the chart image to the temporary directory

              ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());

              //If the last parameter is null, the chart is a "one time"-chart and will be deleted after the first serving.

              //If the last parameter is a session object, the chart remains until session time out.

              filename = ServletUtilities.saveChartAsPNG(chart, width, height, info, session);

    //  Write the image map to the PrintWriter

              ChartUtilities.writeImageMap(pw, filename, info,true);

              pw.flush();

           } catch (Exception e) {

              System.out.println("Exception - " + e.toString());

              e.printStackTrace(System.out);

              filename = "picture_error.png";

           }

           return filename;

       }

}

2 .在页面里

统计好dataset,传到页面。

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<%@ page import="com.jfreechart.util.ChartUtil"%>

<%@ page import="org.jfree.data.general.DefaultPieDataset"%>

<%@ page import = "java.io.PrintWriter" %>

<%

    DefaultPieDataset piedataset=(DefaultPieDataset)request.getAttribute("piedataset");

%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <base href="<%=basePath%>">

    <title>chartDemo.jsp</title>

    <meta http-equiv="pragma" content="no-cache">

    <meta http-equiv="cache-control" content="no-cache">

    <meta http-equiv="expires" content="0">

    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">

    <meta http-equiv="description" content="This is my page">

   <!--

    <link rel="stylesheet" type="text/css" href="styles.css">

    -->

  </head>

<body>

    <%

    // ChartUtil工具类输出

    String p = ChartUtil.generatePieChart(piedataset," 项目收支线图",500,300,null, new PrintWriter(out));

    String p1 = request.getContextPath() + "/servlet/DisplayChart?filename=" + p;

    %>

    <TABLE>

       <tr>

    <td><img src="<%= p1 %>" width=500 height=300 border=0 usemap="#<%= p %>"></td>

    </tr>

    </TABLE>

  </body>

</html>

3 .在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>

5) ApplicationFrame 方式

package com.taiji.jfreechart.frame.example;

import java.awt.Font;

import javax.swing.JPanel;

import org.jfree.chart.ChartFactory;

import org.jfree.chart.ChartPanel;

import org.jfree.chart.JFreeChart;

import org.jfree.chart.plot.PiePlot;

import org.jfree.data.general.DefaultPieDataset;

import org.jfree.data.general.PieDataset;

import org.jfree.ui.ApplicationFrame;

import org.jfree.ui.RefineryUtilities;

/**

 * A simple demonstration application showing how to create a pie chart using

 * data from a {@link DefaultPieDataset}.

 */

public class PieChartDemo1 extends ApplicationFrame {

  /**

     * Default constructor.

     *

     * @param title  the frame title.

     */

    public PieChartDemo1(String title) {

        super(title);

        setContentPane(createDemoPanel());

    }

  /**

     * Creates a sample dataset.

     *

     * @return A sample dataset.

     */

    private static PieDataset createDataset() {

        DefaultPieDataset dataset = new DefaultPieDataset();

        dataset.setValue("One", new Double(43.2));

        dataset.setValue("Two", new Double(10.0));

        dataset.setValue("Three", new Double(27.5));

        dataset.setValue("Four", new Double(17.5));

        dataset.setValue("Five", new Double(11.0));

        dataset.setValue("Six", new Double(19.4));

        return dataset;       

    }

  /**

     * Creates a chart.

     *

     * @param dataset  the dataset.

     *

     * @return A chart.

     */

    private static JFreeChart createChart(PieDataset dataset) {

    JFreeChart chart = ChartFactory.createPieChart(

            "Pie Chart Demo 1",  // chart title

            dataset,             // data

            true,               // include legend

            true,

            false

        );

    PiePlot plot = (PiePlot) chart.getPlot();

        plot.setSectionOutlinesVisible(false);

        plot.setLabelFont(new Font("SansSerif", Font.PLAIN, 12));

        plot.setNoDataMessage("No data available");

        plot.setCircular(false);

        plot.setLabelGap(0.02);

        return chart;

       

    }

 /**

     * Creates a panel for the demo (used by SuperDemo.java).

     *

     * @return A panel.

     */

    public static JPanel createDemoPanel() {

        JFreeChart chart = createChart(createDataset());

        return new ChartPanel(chart);

    }

  /**

     * Starting point for the demonstration application.

     *

     * @param args  ignored.

     */

    public static void main(String[] args) {

        PieChartDemo1 demo = new PieChartDemo1("Pie Chart Demo 1");

        demo.pack();

        RefineryUtilities.centerFrameOnScreen(demo);

        demo.setVisible(true);

    }

}

六. 可参考资料与网址

官方网站

http://www.jfree.org/jfreechart/index.html

   官方论坛

http://www.jfree.org/phpBB2/index.php

API 文档

http://www.jfree.org/jfreechart/api/gjdoc/index.html


   中文API

    
http://blog.sina.com.cn/u/405da78d010000ap

好了,唠叨了这么多,写东西真tmd



posted on 2006-08-16 10:44 阿成 阅读(950) 评论(0)  编辑  收藏 所属分类: Open source

只有注册用户登录后才能发表评论。


网站导航: