<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    The important thing in life is to have a great aim , and the determination

    常用鏈接

    統計

    IT技術鏈接

    保險相關

    友情鏈接

    基金知識

    生活相關

    最新評論

    #

    Spring多數據源解決方案

    在很多大型應用中都會對數據進行切分,并且采用多個數據庫實例進行管理,這樣可以有效提高系統的水平伸縮性。而這樣的方案就會不同于常見的單一數據實例的方案,這就要程序在運行時根據當時的請求及系統狀態來動態的決定將數據存儲在哪個數據庫實例中,以及從哪個數據庫提取數據。

     

    Figure 1 數據分割及多數據庫架構

        通常這種多數據源的邏輯會滲透到業務邏輯中,同時也會給我們使用的數據訪問API諸如Hibernate和iBatis等帶來不便(需要指定多個SessionFactory或SqlMapClient實例來對應多個DataSource)。


    Figure 2 多數據源的選擇邏輯滲透至客戶端

     

        解決方案


    Figure 3 采用Proxy模式來封裝數據源選擇邏輯

        通過采用Proxy模式我們在方案中實現一個虛擬的數據源,并且用它來封裝數據源選擇邏輯,這樣就可以有效地將數據源選擇邏輯從Client中分離出來。

        Client提供選擇所需的上下文(因為這是Client所知道的),由虛擬的DataSource根據Client提供的上下文來實現數據源的選擇。

        Spring2.x的版本中提供了實現這種方式的基本框架,虛擬的DataSource僅需繼承AbstractRoutingDataSource實現determineCurrentLookupKey()在其中封裝數據源的選擇邏輯。

        實例:

    publicclass DynamicDataSource extends AbstractRoutingDataSource {

          static Logger log = Logger.getLogger("DynamicDataSource");

          @Override

          protected Object determineCurrentLookupKey() {

                String userId=(String)DbContextHolder.getContext();

                Integer dataSourceId=getDataSourceIdByUserId(userId);

                return dataSourceId;

          }

    }

        實例中通過UserId來決定數據存放在哪個數據庫中。

        配置文件示例:

    <bean id="dataSource" class="com.bitfone.smartdm.datasource.DynamicDataSource">

                  <property name="targetDataSources">

                     <map key-type="java.lang.Integer">

                        <entry key="0" value-ref="dataSource0"/>

                        <entry key="1" value-ref="dataSource1"/>

                        <entry key="2" value-ref="dataSource2"/>

                     </map>

                  </property>

                  <property name="defaultTargetDataSource" ref="dataSource0"/>

                </bean>

                <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">

                    <property name="configLocation" value="classpath:com/bitfone/smartdm/dao/sqlmap/sql-map-config.xml"/>

                    <property name="dataSource" ref="dataSource"/>

               </bean>

                <bean id="UserInfoDAO" class="com.bitfone.smartdm.dao.impl.UserInfoDAO">

     

                      <property name="sqlMapClient" ref="sqlMapClient"/>

                </bean>

    posted @ 2010-07-14 17:10 鴻雁 閱讀(130) | 評論 (0)編輯 收藏

    使用JAVA中的動態代理實現數據庫連接池(轉自developerWorks )

         摘要:   通過使用JAVA中的動態代理實現數據庫連接池,使使用者可以以普通的jdbc連接的使用習慣來使用連接池。 數據庫連接池在編寫應用服務是經常需要用到的模塊,太過頻繁的連接數據庫對服務性能來講是一個瓶頸,使用緩沖池技術可以來消除這個瓶頸。我們可以在互聯網上找到很多關于數據庫連接池的源程序,但是都發現這樣一個共同的問題:這些連接池的實現方法都不同程度地增加了與使用者之間的耦合度。很多的連...  閱讀全文

    posted @ 2010-07-14 17:08 鴻雁 閱讀(150) | 評論 (0)編輯 收藏

    jfreechart 生成折線圖,餅圖,柱狀圖,堆棧柱狀圖(轉自javaEye)

    1.所需包
    (1) jfreechart-1.0.8a.jar
    (2) jcommon-1.0.12.jar
    2.運行環境
    JDK 1.5

    3.源代碼

    import java.awt.Color;
    import java.awt.Font;
    import java.io.File;
    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.axis.CategoryAxis;
    import org.jfree.chart.axis.CategoryLabelPositions;
    import org.jfree.chart.axis.NumberAxis;
    import org.jfree.chart.axis.ValueAxis;
    import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
    import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
    import org.jfree.chart.plot.CategoryPlot;
    import org.jfree.chart.plot.PiePlot3D;
    import org.jfree.chart.plot.PlotOrientation;
    import org.jfree.chart.renderer.category.BarRenderer;
    import org.jfree.chart.renderer.category.LineAndShapeRenderer;
    import org.jfree.chart.renderer.category.StackedBarRenderer;
    import org.jfree.chart.title.TextTitle;
    import org.jfree.data.category.CategoryDataset;
    import org.jfree.data.general.DatasetUtilities;
    import org.jfree.data.general.DefaultPieDataset;
    import org.jfree.data.general.PieDataset;

    /**
    * 實際取色的時候一定要16位的,這樣比較準確
    *
    * @author new
    */
    public class CreateChartServiceImpl
    {
    private static final String CHART_PATH = "E:/test/";

    public static void main(String[] args)
    {
    // TODO Auto-generated method stub
    CreateChartServiceImpl pm = new CreateChartServiceImpl();
    // 生成餅狀圖
    pm.makePieChart();
    // 生成單組柱狀圖
    pm.makeBarChart();
    // 生成多組柱狀圖
    pm.makeBarGroupChart();
    // 生成堆積柱狀圖
    pm.makeStackedBarChart();
    // 生成折線圖
    pm.makeLineAndShapeChart();
    }

    /**
    * 生成折線圖
    */
    public void makeLineAndShapeChart()
    {
    double[][] data = new double[][]
    {
    { 672, 766, 223, 540, 126 },
    { 325, 521, 210, 340, 106 },
    { 332, 256, 523, 240, 526 } };
    String[] rowKeys =
    { "蘋果", "梨子", "葡萄" };
    String[] columnKeys =
    { "北京", "上海", "廣州", "成都", "深圳" };
    CategoryDataset dataset = getBarData(data, rowKeys, columnKeys);
    createTimeXYChar("折線圖", "x軸", "y軸", dataset, "lineAndShap.png");
    }

    /**
    * 生成分組的柱狀圖
    */
    public void makeBarGroupChart()
    {
    double[][] data = new double[][]
    {
    { 672, 766, 223, 540, 126 },
    { 325, 521, 210, 340, 106 },
    { 332, 256, 523, 240, 526 } };
    String[] rowKeys =
    { "蘋果", "梨子", "葡萄" };
    String[] columnKeys =
    { "北京", "上海", "廣州", "成都", "深圳" };
    CategoryDataset dataset = getBarData(data, rowKeys, columnKeys);
    createBarChart(dataset, "x坐標", "y坐標", "柱狀圖", "barGroup.png");
    }

    /**
    * 生成柱狀圖
    */
    public void makeBarChart()
    {
    double[][] data = new double[][]
    {
    { 672, 766, 223, 540, 126 } };
    String[] rowKeys =
    { "蘋果" };
    String[] columnKeys =
    { "北京", "上海", "廣州", "成都", "深圳" };
    CategoryDataset dataset = getBarData(data, rowKeys, columnKeys);
    createBarChart(dataset, "x坐標", "y坐標", "柱狀圖", "bar.png");
    }

    /**
    * 生成堆棧柱狀圖
    */
    public void makeStackedBarChart()
    {
    double[][] data = new double[][]
    {
    { 0.21, 0.66, 0.23, 0.40, 0.26 },
    { 0.25, 0.21, 0.10, 0.40, 0.16 } };
    String[] rowKeys =
    { "蘋果", "梨子" };
    String[] columnKeys =
    { "北京", "上海", "廣州", "成都", "深圳" };
    CategoryDataset dataset = getBarData(data, rowKeys, columnKeys);
    createStackedBarChart(dataset, "x坐標", "y坐標", "柱狀圖", "stsckedBar.png");
    }

    /**
    * 生成餅狀圖
    */
    public void makePieChart()
    {
    double[] data =
    { 9, 91 };
    String[] keys =
    { "失敗率", "成功率" };

    createValidityComparePimChar(getDataPieSetByUtil(data, keys), "餅狀圖",
            "pie2.png", keys);
    }

    // 柱狀圖,折線圖 數據集
    public CategoryDataset getBarData(double[][] data, String[] rowKeys,
            String[] columnKeys)
    {
    return DatasetUtilities
            .createCategoryDataset(rowKeys, columnKeys, data);

    }

    // 餅狀圖 數據集
    public PieDataset getDataPieSetByUtil(double[] data,
            String[] datadescription)
    {

    if (data != null && datadescription != null)
    {
    if (data.length == datadescription.length)
    {
    DefaultPieDataset dataset = new DefaultPieDataset();
    for (int i = 0; i < data.length; i++)
    {
    dataset.setValue(datadescription[i], data[i]);
    }
    return dataset;
    }

    }

    return null;
    }

    /**
    * 柱狀圖
    *
    *@param dataset 數據集
    * @param xName x軸的說明(如種類,時間等)
    * @param yName y軸的說明(如速度,時間等)
    * @param chartTitle 圖標題
    * @param charName 生成圖片的名字
    * @return
    */
    public String createBarChart(CategoryDataset dataset, String xName,
            String yName, String chartTitle, String charName)
    {
    JFreeChart chart = ChartFactory.createBarChart(chartTitle, // 圖表標題
            xName, // 目錄軸的顯示標簽
            yName, // 數值軸的顯示標簽
            dataset, // 數據集
            PlotOrientation.VERTICAL, // 圖表方向:水平、垂直
            true, // 是否顯示圖例(對于簡單的柱狀圖必須是false)
            false, // 是否生成工具
            false // 是否生成URL鏈接
            );
    Font labelFont = new Font("SansSerif", Font.TRUETYPE_FONT, 12);
    /*
    * VALUE_TEXT_ANTIALIAS_OFF表示將文字的抗鋸齒關閉,
    * 使用的關閉抗鋸齒后,字體盡量選擇12到14號的宋體字,這樣文字最清晰好看
    */
    // chart.getRenderingHints().put(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
    chart.setTextAntiAlias(false);
    chart.setBackgroundPaint(Color.white);
    // create plot
    CategoryPlot plot = chart.getCategoryPlot();
    // 設置橫虛線可見
    plot.setRangeGridlinesVisible(true);
    // 虛線色彩
    plot.setRangeGridlinePaint(Color.gray);

    // 數據軸精度
    NumberAxis vn = (NumberAxis) plot.getRangeAxis();
    // vn.setAutoRangeIncludesZero(true);
    DecimalFormat df = new DecimalFormat("#0.00");
    vn.setNumberFormatOverride(df); // 數據軸數據標簽的顯示格式
    // x軸設置
    CategoryAxis domainAxis = plot.getDomainAxis();
    domainAxis.setLabelFont(labelFont);// 軸標題
    domainAxis.setTickLabelFont(labelFont);// 軸數值

    // Lable(Math.PI/3.0)度傾斜
    // domainAxis.setCategoryLabelPositions(CategoryLabelPositions
    // .createUpRotationLabelPositions(Math.PI / 3.0));

    domainAxis.setMaximumCategoryLabelWidthRatio(0.6f);// 橫軸上的 Lable 是否完整顯示

    // 設置距離圖片左端距離
    domainAxis.setLowerMargin(0.1);
    // 設置距離圖片右端距離
    domainAxis.setUpperMargin(0.1);
    // 設置 columnKey 是否間隔顯示
    // domainAxis.setSkipCategoryLabelsToFit(true);

    plot.setDomainAxis(domainAxis);
    // 設置柱圖背景色(注意,系統取色的時候要使用16位的模式來查看顏色編碼,這樣比較準確)
    plot.setBackgroundPaint(new Color(255, 255, 204));

    // y軸設置
    ValueAxis rangeAxis = plot.getRangeAxis();
    rangeAxis.setLabelFont(labelFont);
    rangeAxis.setTickLabelFont(labelFont);
    // 設置最高的一個 Item 與圖片頂端的距離
    rangeAxis.setUpperMargin(0.15);
    // 設置最低的一個 Item 與圖片底端的距離
    rangeAxis.setLowerMargin(0.15);
    plot.setRangeAxis(rangeAxis);

    BarRenderer renderer = new BarRenderer();
    // 設置柱子寬度
    renderer.setMaximumBarWidth(0.05);
    // 設置柱子高度
    renderer.setMinimumBarLength(0.2);
    // 設置柱子邊框顏色
    renderer.setBaseOutlinePaint(Color.BLACK);
    // 設置柱子邊框可見
    renderer.setDrawBarOutline(true);

    // // 設置柱的顏色
    renderer.setSeriesPaint(0, new Color(204, 255, 255));
    renderer.setSeriesPaint(1, new Color(153, 204, 255));
    renderer.setSeriesPaint(2, new Color(51, 204, 204));

    // 設置每個地區所包含的平行柱的之間距離
    renderer.setItemMargin(0.0);

    // 顯示每個柱的數值,并修改該數值的字體屬性
    renderer.setIncludeBaseInRange(true);
    renderer
            .setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());
    renderer.setBaseItemLabelsVisible(true);

    plot.setRenderer(renderer);
    // 設置柱的透明度
    plot.setForegroundAlpha(1.0f);

    FileOutputStream fos_jpg = null;
    try
    {
    isChartPathExist(CHART_PATH);
    String chartName = CHART_PATH + charName;
    fos_jpg = new FileOutputStream(chartName);
    ChartUtilities.writeChartAsPNG(fos_jpg, chart, 500, 500, true, 10);
    return chartName;
    }
    catch (Exception e)
    {
    e.printStackTrace();
    return null;
    }
    finally
    {
    try
    {
    fos_jpg.close();
    }
    catch (Exception e)
    {
    e.printStackTrace();
    }
    }
    }

    /**
    * 橫向圖
    *
    * @param dataset 數據集
    * @param xName x軸的說明(如種類,時間等)
    * @param yName y軸的說明(如速度,時間等)
    * @param chartTitle 圖標題
    * @param charName 生成圖片的名字
    * @return
    */
    public String createHorizontalBarChart(CategoryDataset dataset,
            String xName, String yName, String chartTitle, String charName)
    {
    JFreeChart chart = ChartFactory.createBarChart(chartTitle, // 圖表標題
            xName, // 目錄軸的顯示標簽
            yName, // 數值軸的顯示標簽
            dataset, // 數據集
            PlotOrientation.VERTICAL, // 圖表方向:水平、垂直
            true, // 是否顯示圖例(對于簡單的柱狀圖必須是false)
            false, // 是否生成工具
            false // 是否生成URL鏈接
            );

    CategoryPlot plot = chart.getCategoryPlot();
    // 數據軸精度
    NumberAxis vn = (NumberAxis) plot.getRangeAxis();
    //設置刻度必須從0開始
    // vn.setAutoRangeIncludesZero(true);
    DecimalFormat df = new DecimalFormat("#0.00");
    vn.setNumberFormatOverride(df); // 數據軸數據標簽的顯示格式

    CategoryAxis domainAxis = plot.getDomainAxis();

    domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45); // 橫軸上的
    // Lable
    Font labelFont = new Font("SansSerif", Font.TRUETYPE_FONT, 12);

    domainAxis.setLabelFont(labelFont);// 軸標題
    domainAxis.setTickLabelFont(labelFont);// 軸數值

    domainAxis.setMaximumCategoryLabelWidthRatio(0.8f);// 橫軸上的 Lable 是否完整顯示
    // domainAxis.setVerticalCategoryLabels(false);
    plot.setDomainAxis(domainAxis);

    ValueAxis rangeAxis = plot.getRangeAxis();
    // 設置最高的一個 Item 與圖片頂端的距離
    rangeAxis.setUpperMargin(0.15);
    // 設置最低的一個 Item 與圖片底端的距離
    rangeAxis.setLowerMargin(0.15);
    plot.setRangeAxis(rangeAxis);
    BarRenderer renderer = new BarRenderer();
    // 設置柱子寬度
    renderer.setMaximumBarWidth(0.03);
    // 設置柱子高度
    renderer.setMinimumBarLength(30);

    renderer.setBaseOutlinePaint(Color.BLACK);

    // 設置柱的顏色
    renderer.setSeriesPaint(0, Color.GREEN);
    renderer.setSeriesPaint(1, new Color(0, 0, 255));
    // 設置每個地區所包含的平行柱的之間距離
    renderer.setItemMargin(0.5);
    // 顯示每個柱的數值,并修改該數值的字體屬性
    renderer
            .setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());
    // 設置柱的數值可見
    renderer.setBaseItemLabelsVisible(true);

    plot.setRenderer(renderer);
    // 設置柱的透明度
    plot.setForegroundAlpha(0.6f);

    FileOutputStream fos_jpg = null;
    try
    {
    isChartPathExist(CHART_PATH);
    String chartName = CHART_PATH + charName;
    fos_jpg = new FileOutputStream(chartName);
    ChartUtilities.writeChartAsPNG(fos_jpg, chart, 500, 500, true, 10);
    return chartName;
    }
    catch (Exception e)
    {
    e.printStackTrace();
    return null;
    }
    finally
    {
    try
    {
    fos_jpg.close();
    }
    catch (Exception e)
    {
    e.printStackTrace();
    }
    }
    }

    /**
    * 餅狀圖
    *
    * @param dataset 數據集
    * @param chartTitle 圖標題
    * @param charName 生成圖的名字
    * @param pieKeys 分餅的名字集
    * @return
    */
    public String createValidityComparePimChar(PieDataset dataset,
            String chartTitle, String charName, String[] pieKeys)
    {
    JFreeChart chart = ChartFactory.createPieChart3D(chartTitle, // chart
            // title
            dataset,// data
            true,// include legend
            true, false);

    // 使下說明標簽字體清晰,去鋸齒類似于
    // chart.getRenderingHints().put(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);的效果
    chart.setTextAntiAlias(false);
    // 圖片背景色
    chart.setBackgroundPaint(Color.white);
    // 設置圖標題的字體重新設置title
    Font font = new Font("隸書", Font.BOLD, 25);
    TextTitle title = new TextTitle(chartTitle);
    title.setFont(font);
    chart.setTitle(title);

    PiePlot3D plot = (PiePlot3D) chart.getPlot();
    // 圖片中顯示百分比:默認方式

    // 指定餅圖輪廓線的顏色
    // plot.setBaseSectionOutlinePaint(Color.BLACK);
    // plot.setBaseSectionPaint(Color.BLACK);

    // 設置無數據時的信息
    plot.setNoDataMessage("無對應的數據,請重新查詢。");

    // 設置無數據時的信息顯示顏色
    plot.setNoDataMessagePaint(Color.red);

    // 圖片中顯示百分比:自定義方式,{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})"));

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

    // 指定圖片的透明度(0.0-1.0)
    plot.setForegroundAlpha(0.65f);
    // 指定顯示的餅圖上圓形(false)還橢圓形(true)
    plot.setCircular(false, true);

    // 設置第一個 餅塊section 的開始位置,默認是12點鐘方向
    plot.setStartAngle(90);

    // // 設置分餅顏色
    plot.setSectionPaint(pieKeys[0], new Color(244, 194, 144));
    plot.setSectionPaint(pieKeys[1], new Color(144, 233, 144));

    FileOutputStream fos_jpg = null;
    try
    {
    // 文件夾不存在則創建
    isChartPathExist(CHART_PATH);
    String chartName = CHART_PATH + charName;
    fos_jpg = new FileOutputStream(chartName);
    // 高寬的設置影響橢圓餅圖的形狀
    ChartUtilities.writeChartAsPNG(fos_jpg, chart, 500, 230);

    return chartName;
    }
    catch (Exception e)
    {
    e.printStackTrace();
    return null;
    }
    finally
    {
    try
    {
    fos_jpg.close();
    System.out.println("create pie-chart.");
    }
    catch (Exception e)
    {
    e.printStackTrace();
    }
    }

    }

    /**
    * 判斷文件夾是否存在,如果不存在則新建
    * @param chartPath
    */
    private void isChartPathExist(String chartPath)
    {
    File file = new File(chartPath);
    if (!file.exists())
    {
    file.mkdirs();
    // log.info("CHART_PATH="+CHART_PATH+"create.");
    }
    }

    /**
    * 折線圖
    *
    * @param chartTitle
    * @param x
    * @param y
    * @param xyDataset
    * @param charName
    * @return
    */
    public String createTimeXYChar(String chartTitle, String x, String y,
            CategoryDataset xyDataset, String charName)
    {

    JFreeChart chart = ChartFactory.createLineChart(chartTitle, x, y,
            xyDataset, PlotOrientation.VERTICAL, true, true, false);

    chart.setTextAntiAlias(false);
    chart.setBackgroundPaint(Color.WHITE);
    // 設置圖標題的字體重新設置title
    Font font = new Font("隸書", Font.BOLD, 25);
    TextTitle title = new TextTitle(chartTitle);
    title.setFont(font);
    chart.setTitle(title);
    // 設置面板字體
    Font labelFont = new Font("SansSerif", Font.TRUETYPE_FONT, 12);

    chart.setBackgroundPaint(Color.WHITE);

    CategoryPlot categoryplot = (CategoryPlot) chart.getPlot();
    // x軸 // 分類軸網格是否可見
    categoryplot.setDomainGridlinesVisible(true);
    // y軸 //數據軸網格是否可見
    categoryplot.setRangeGridlinesVisible(true);

    categoryplot.setRangeGridlinePaint(Color.WHITE);// 虛線色彩

    categoryplot.setDomainGridlinePaint(Color.WHITE);// 虛線色彩

    categoryplot.setBackgroundPaint(Color.lightGray);

    // 設置軸和面板之間的距離
    // categoryplot.setAxisOffset(new RectangleInsets(5D, 5D, 5D, 5D));

    CategoryAxis domainAxis = categoryplot.getDomainAxis();

    domainAxis.setLabelFont(labelFont);// 軸標題
    domainAxis.setTickLabelFont(labelFont);// 軸數值

    domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45); // 橫軸上的
    // Lable
    // 45度傾斜
    // 設置距離圖片左端距離
    domainAxis.setLowerMargin(0.0);
    // 設置距離圖片右端距離
    domainAxis.setUpperMargin(0.0);

    NumberAxis numberaxis = (NumberAxis) categoryplot.getRangeAxis();
    numberaxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
    numberaxis.setAutoRangeIncludesZero(true);

    // 獲得renderer 注意這里是下嗍造型到lineandshaperenderer!!
    LineAndShapeRenderer lineandshaperenderer = (LineAndShapeRenderer) categoryplot
            .getRenderer();

    lineandshaperenderer.setBaseShapesVisible(true); // series 點(即數據點)可見
    lineandshaperenderer.setBaseLinesVisible(true); // series 點(即數據點)間有連線可見

    // 顯示折點數據
    // lineandshaperenderer.setBaseItemLabelGenerator(new
    // StandardCategoryItemLabelGenerator());
    // lineandshaperenderer.setBaseItemLabelsVisible(true);

    FileOutputStream fos_jpg = null;
    try
    {
    isChartPathExist(CHART_PATH);
    String chartName = CHART_PATH + charName;
    fos_jpg = new FileOutputStream(chartName);

    // 將報表保存為png文件
    ChartUtilities.writeChartAsPNG(fos_jpg, chart, 500, 510);

    return chartName;
    }
    catch (Exception e)
    {
    e.printStackTrace();
    return null;
    }
    finally
    {
    try
    {
    fos_jpg.close();
    System.out.println("create time-createTimeXYChar.");
    }
    catch (Exception e)
    {
    e.printStackTrace();
    }
    }
    }

    /**
    * 堆棧柱狀圖
    *
    * @param dataset
    * @param xName
    * @param yName
    * @param chartTitle
    * @param charName
    * @return
    */
    public String createStackedBarChart(CategoryDataset dataset, String xName,
            String yName, String chartTitle, String charName)
    {
    // 1:得到 CategoryDataset

    // 2:JFreeChart對象
    JFreeChart chart = ChartFactory.createStackedBarChart(chartTitle, // 圖表標題
            xName, // 目錄軸的顯示標簽
            yName, // 數值軸的顯示標簽
            dataset, // 數據集
            PlotOrientation.VERTICAL, // 圖表方向:水平、垂直
            true, // 是否顯示圖例(對于簡單的柱狀圖必須是false)
            false, // 是否生成工具
            false // 是否生成URL鏈接
            );
    // 圖例字體清晰
    chart.setTextAntiAlias(false);

    chart.setBackgroundPaint(Color.WHITE);

    // 2 .2 主標題對象 主標題對象是 TextTitle 類型
    chart
            .setTitle(new TextTitle(chartTitle, new Font("隸書", Font.BOLD,
                    25)));
    // 2 .2.1:設置中文
    // x,y軸坐標字體
    Font labelFont = new Font("SansSerif", Font.TRUETYPE_FONT, 12);

    // 2 .3 Plot 對象 Plot 對象是圖形的繪制結構對象
    CategoryPlot plot = chart.getCategoryPlot();

    // 設置橫虛線可見
    plot.setRangeGridlinesVisible(true);
    // 虛線色彩
    plot.setRangeGridlinePaint(Color.gray);

    // 數據軸精度
    NumberAxis vn = (NumberAxis) plot.getRangeAxis();
    // 設置最大值是1
    vn.setUpperBound(1);
    // 設置數據軸坐標從0開始
    // vn.setAutoRangeIncludesZero(true);
    // 數據顯示格式是百分比
    DecimalFormat df = new DecimalFormat("0.00%");
    vn.setNumberFormatOverride(df); // 數據軸數據標簽的顯示格式
    // DomainAxis (區域軸,相當于 x 軸), RangeAxis (范圍軸,相當于 y 軸)
    CategoryAxis domainAxis = plot.getDomainAxis();

    domainAxis.setLabelFont(labelFont);// 軸標題
    domainAxis.setTickLabelFont(labelFont);// 軸數值

    // x軸坐標太長,建議設置傾斜,如下兩種方式選其一,兩種效果相同
    // 傾斜(1)橫軸上的 Lable 45度傾斜
    // domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45);
    // 傾斜(2)Lable(Math.PI 3.0)度傾斜
    // domainAxis.setCategoryLabelPositions(CategoryLabelPositions
    // .createUpRotationLabelPositions(Math.PI / 3.0));

    domainAxis.setMaximumCategoryLabelWidthRatio(0.6f);// 橫軸上的 Lable 是否完整顯示

    plot.setDomainAxis(domainAxis);

    // y軸設置
    ValueAxis rangeAxis = plot.getRangeAxis();
    rangeAxis.setLabelFont(labelFont);
    rangeAxis.setTickLabelFont(labelFont);
    // 設置最高的一個 Item 與圖片頂端的距離
    rangeAxis.setUpperMargin(0.15);
    // 設置最低的一個 Item 與圖片底端的距離
    rangeAxis.setLowerMargin(0.15);
    plot.setRangeAxis(rangeAxis);

    // Renderer 對象是圖形的繪制單元
    StackedBarRenderer renderer = new StackedBarRenderer();
    // 設置柱子寬度
    renderer.setMaximumBarWidth(0.05);
    // 設置柱子高度
    renderer.setMinimumBarLength(0.1);
            //設置柱的邊框顏色
    renderer.setBaseOutlinePaint(Color.BLACK);
    //設置柱的邊框可見
    renderer.setDrawBarOutline(true);

    // // 設置柱的顏色(可設定也可默認)
    renderer.setSeriesPaint(0, new Color(204, 255, 204));
    renderer.setSeriesPaint(1, new Color(255, 204, 153));

    // 設置每個地區所包含的平行柱的之間距離
    renderer.setItemMargin(0.4);

    plot.setRenderer(renderer);
    // 設置柱的透明度(如果是3D的必須設置才能達到立體效果,如果是2D的設置則使顏色變淡)
    // plot.setForegroundAlpha(0.65f);

    FileOutputStream fos_jpg = null;
    try
    {
    isChartPathExist(CHART_PATH);
    String chartName = CHART_PATH + charName;
    fos_jpg = new FileOutputStream(chartName);
    ChartUtilities.writeChartAsPNG(fos_jpg, chart, 500, 500, true, 10);
    return chartName;
    }
    catch (Exception e)
    {
    e.printStackTrace();
    return null;
    }
    finally
    {
    try
    {
    fos_jpg.close();
    }
    catch (Exception e)
    {
    e.printStackTrace();
    }
    }
    }

    }

    posted @ 2009-11-12 15:25 鴻雁 閱讀(953) | 評論 (0)編輯 收藏

    阿里要走102年 阿里的工程師能走多遠?(轉)

    很高興看到阿里云的成立。這意味著阿里已經把對互聯網技術的投入提高到了的戰略高度。過去經常聽工程師抱怨阿里不是一家技術公司。現在再沒有理由可以這樣抱怨了。但是要實現這個戰略,沒有技術儲備是不行的。招聘和培養工程師顯然是目前集團各子公司同時面臨的一個令人頭痛的難題。

    由于曾經在硅谷工作過,我常想,為什么硅谷有這么多40歲以上的工程師,而國內30歲以上的就已經寥寥無幾了?為什么硅谷的工程師的技術壽命可以這么長?為什么他們可以不浮躁,不急功近利呢?阿里要走102年,阿里的工程師可以一起走多遠呢?

    在國內,有2-3年工作經歷的工程師就可以算有經驗的了。工作了5年以上的工程師往往會考慮向管理崗位轉型,或者向業務轉型。中國目前處于高度發展的階段。很多企業缺乏管理人才,工作5年就被提吧為干部很正常。但留下的后遺癥是30歲以上的優秀技術人才極度缺乏。

    在硅谷,5年以下工作經驗的人都算是初級的。一般高級工程師需要5年以上的工作經驗,架構師一般需要10年以上的工作經驗。這還不算上大部分硅谷的工程師都有計算機碩士學位。畢業的時候一般已經是24,25歲了。再工作10年,35歲才升為架構師是非常正常的。然而,公司里的架構師有限。其實大部分 40歲的工程師仍然在一線工作,比如寫程序,做測試,進行項目管理等。

    美國硅谷是計算機人才集中的地方,也是創業公司群集的地方。在硅谷,從只有幾個人到幾十個人的創業公司比比皆是。他們的共同夢想就是經過幾年的奮斗,通過技術的創新,再次締造像英特爾,蘋果,思科,甲骨文,雅虎,Google,Facebook等這樣的神話。即使創造不了神話,也可以通過IPO或者被收購的途徑創造財富。在這樣的環境中,公司對管理人才的需求同樣是非常大的,但為什么仍然有大量的工程師“無動于衷”,仍然從事著技術活兒呢?

    我認為有兩個主要原因。

    一個是外因。在美國,管理崗位的待遇和技術崗位待遇相差不大。特別在崇尚技術的硅谷,經理的地位并不比工程師高,甚至更低。比如架構師在公司里的重要性往往要超過經理。因此管理崗位的“誘惑”并不大。在這樣一種技術氛圍中,走技術路線很正常。

    但是即使在這樣一個技術環境中,硅谷對管理人才依然需要。當工程師表現出色時,也有很多機會轉成管理崗位。然而相當一部分工程師會主動放棄這樣的機會,而繼續干他們的技術活兒。這就是內因在驅動了。技術工作和管理工作的本質區別是,前者面對的是系統(軟件,硬件等),而后者面對的是人。系統問題再難,只要有足夠的時間和資源,一般都可以解決。越難的問題,解決之后越有成就感。而人的問題,有時候看似很簡單,卻解決不了。是人,總要有頭疼腦熱,生病的時候。是人,免不了產生情緒,從而影響工作。有人的地方,就會有矛盾,就會有摩擦。簡單地講,系統會按照事先設定的邏輯運行,是死的,因此往往可控,可規劃。而人是活的,不是輸入幾條命令就可以控制的,而是需要溝通,需要感情的。因此,大部分硅谷的工程師很“聰明”。他們主動選擇“簡單”地工作。白天好好地工作,晚上好好地生活。何必去“自尋煩惱”,轉做管理呢。

    其實不光是硅谷的,其它地區的工程師都有一個共同的性格特點,追求簡單,追求完美,思維方式上比較理性和邏輯性,看問題比較趨向于非黑即白。這樣的性格非常適合做技術工作,可是我們中國的工程師有時候偏偏看不到自己的這個特點。

    不想當元帥的士兵不是好士兵。工程師希望向管理方向發展是非常正常的。但問題是為什么和怎樣?我碰到過不只一個工程師告訴我,希望轉做管理的原因是擔心今后年級大了,技術能力跟不上了。我覺得非常可笑。這就好比是一個士兵說:我殺敵本領不行,不適合上戰場,那就讓我做軍官吧。一個沒做過士兵的元帥肯定不是好元帥。其實做技術和當兵畢竟不同,不是靠體力吃飯的。年級大點往往是優勢。

    我覺得走技術路線對工程師性格的人是一條捷徑。如果能靜下心來仔細鉆研技術,一定能在某個方面做得比別人好。這里的關鍵是好奇心和耐心。在今天這樣的信息時代,找到答案并不是一件難事。難就難在有沒有好奇心和耐心去找。比如,Java程序員天天都用到String這個類型。但有沒有想過為什么 Java語言里有String和StringBuffer兩種字符串類型,而不是一種?有沒有去看過String和StringBuffer的源代碼?再例如,天天做網站和HTTP打交道,有沒有看過HTTP協議?有沒有嘗試過不用瀏覽器,wget等工具,而用最原始的telnet方式來訪問網站?看看這 HTTP的頭里到底是什么東東?在我面試過的工程師中,做過這幾件事的人不到5%。

    一旦了解得比別人深,就容易看到問題本質,產生信心,激發樂趣。這時候你的解決方案就比別人漂亮,逐漸建立起了影響力,成為了“專家”。因此公司里的疑難雜癥會主動找上門來。你就比別人得到了更多的解決問題的機會,從而更快地提升能力。一旦進入良性循環,你的進步就比別人快,但付出的卻不一定比別人多。這時候你已經走上了捷徑。

    在技術人才極度缺乏的中國,在眾人盲目追求管理崗位的那點虛榮的今天,如果你的性格是工程師類型的,走技術路線其實是非常適合的。如果你才畢業,那你是最幸福的。你可以給自己制定3個甚至4個五年計劃。例如5年打基礎,10年變專家,15年國內知名,20年世界聞名。如果你已經奔三或者三十出頭,那你快成熟了,但離開花結果還早呢。不信你看看下面幾位我們都熟悉的人。

    拉里-沃爾(Larry Wall)33歲時出版了《Perl語言編程》一書。之前他是一個系統管理員。

    互聯網之父溫特-瑟夫(Vint Cerf)在發明TCP/IP時,已經35歲。

    萬維網之父蒂姆·伯納斯—李(Tim Berners-Lee)在37歲時才發明了萬維網(WWW)。

    丹尼斯-里奇(Dennis Ritchie)的《C程序設計語言》一書出版時,他37歲。

    Java之父詹姆斯·戈士林(James Gosling)40歲時才因為發明Java而成名。

    蘋果公司創始人之一史蒂夫?沃茲尼艾克(Steven Wozniak)在今年年初以首席科學家的身份加入一家創業公司,研發基于高速閃存技術的存儲。他如今已經59歲了。

    本文來源:百度博客

    posted @ 2009-10-16 12:36 鴻雁 閱讀(165) | 評論 (0)編輯 收藏

    SQL SERVER convert函數日期格式化應用(轉)

    Sql Server 中一個非常強大的日期格式化函數
    Select CONVERT(varchar(100), GETDATE(), 0): 05 16 2006 10:57AM
    Select CONVERT(varchar(100), GETDATE(), 1): 05/16/06
    Select CONVERT(varchar(100), GETDATE(), 2): 06.05.16
    Select CONVERT(varchar(100), GETDATE(), 3): 16/05/06
    Select CONVERT(varchar(100), GETDATE(), 4): 16.05.06
    Select CONVERT(varchar(100), GETDATE(), 5): 16-05-06
    Select CONVERT(varchar(100), GETDATE(), 6): 16 05 06
    Select CONVERT(varchar(100), GETDATE(), 7): 05 16, 06
    Select CONVERT(varchar(100), GETDATE(), 8): 10:57:46
    Select CONVERT(varchar(100), GETDATE(), 9): 05 16 2006 10:57:46:827AM
    Select CONVERT(varchar(100), GETDATE(), 10): 05-16-06
    Select CONVERT(varchar(100), GETDATE(), 11): 06/05/16
    Select CONVERT(varchar(100), GETDATE(), 12): 060516
    Select CONVERT(varchar(100), GETDATE(), 13): 16 05 2006 10:57:46:937
    Select CONVERT(varchar(100), GETDATE(), 14): 10:57:46:967
    Select CONVERT(varchar(100), GETDATE(), 20): 2006-05-16 10:57:47
    Select CONVERT(varchar(100), GETDATE(), 21): 2006-05-16 10:57:47.157
    Select CONVERT(varchar(100), GETDATE(), 22): 05/16/06 10:57:47 AM
    Select CONVERT(varchar(100), GETDATE(), 23): 2006-05-16
    Select CONVERT(varchar(100), GETDATE(), 24): 10:57:47
    Select CONVERT(varchar(100), GETDATE(), 25): 2006-05-16 10:57:47.250
    Select CONVERT(varchar(100), GETDATE(), 100): 05 16 2006 10:57AM
    Select CONVERT(varchar(100), GETDATE(), 101): 05/16/2006
    Select CONVERT(varchar(100), GETDATE(), 102): 2006.05.16
    Select CONVERT(varchar(100), GETDATE(), 103): 16/05/2006
    Select CONVERT(varchar(100), GETDATE(), 104): 16.05.2006
    Select CONVERT(varchar(100), GETDATE(), 105): 16-05-2006
    Select CONVERT(varchar(100), GETDATE(), 106): 16 05 2006
    Select CONVERT(varchar(100), GETDATE(), 107): 05 16, 2006
    Select CONVERT(varchar(100), GETDATE(), 108): 10:57:49
    Select CONVERT(varchar(100), GETDATE(), 109): 05 16 2006 10:57:49:437AM
    Select CONVERT(varchar(100), GETDATE(), 110): 05-16-2006
    Select CONVERT(varchar(100), GETDATE(), 111): 2006/05/16
    Select CONVERT(varchar(100), GETDATE(), 112): 20060516
    Select CONVERT(varchar(100), GETDATE(), 113): 16 05 2006 10:57:49:513
    Select CONVERT(varchar(100), GETDATE(), 114): 10:57:49:547
    Select CONVERT(varchar(100), GETDATE(), 120): 2006-05-16 10:57:49
    Select CONVERT(varchar(100), GETDATE(), 121): 2006-05-16 10:57:49.700
    Select CONVERT(varchar(100), GETDATE(), 126): 2006-05-16T10:57:49.827
    Select CONVERT(varchar(100), GETDATE(), 130): 18 ???? ?????? 1427 10:57:49:907AM
    Select CONVERT(varchar(100), GETDATE(), 131): 18/04/1427 10:57:49:920AM

    posted @ 2009-09-23 15:14 鴻雁 閱讀(184) | 評論 (0)編輯 收藏

    oracle定時任務詳解(轉自CSDN)

     

    DBMS_JOB系統包是Oracle“任務隊列”子系統的API編程接口。DBMS_JOB包對于任務隊列提供了下面這些功能:提交并且執行一個任務、改變任務的執行參數以及刪除或者臨時掛起任務等。

    DBMS_JOB包是由ORACLE_HOME目錄下的rdbms/admin子目錄下的DBMSJOB.SQL和PRVTJOB.PLB 這兩個腳本文件創建的。這兩個文件被CATPROC.SQL腳本文件調用,而CATPROC.SQL這個文件一般是在數據庫創建后立即執行的。腳本為DBMS_JOB包創建了一個公共同義詞,并給該包授予了公共的可執行權限,所以所有的Oracle用戶均可以使用這個包。

    下面幾個數據字典視圖是關于任務隊列信息的,主要有DBA_JOBS, USER_JOBS和DBA_JOBS_RUNNING。這些字典視圖是由名為CATJOBQ.SQL的腳本文件創建的。該腳本文件和創建DBMS_JOB包的腳本文件一樣在ORACLE_HOME目錄的rdbms/admin子目錄中,同樣也是由腳本文件CATPROC.SQL調用。

    最后,要使任務隊列能正常運行,還必須啟動它自己專有的后臺過程。啟動后臺過程是通過在初始化文件init*.ora(實例不同,初始化文件名也略有不同)中設置初始化參數來進行的。下面就是該參數:

    JOB_QUEUE_PROCESSES = n 

    其中,n可以是0到36之間的任何一個數。除了該參數以外,還有幾個關于任務隊列的初始化參數,本文后面將會對其進行詳細討論。

    DBMS_JOB包中包含有許多過程,見表1所示。

    表1 DBMS_JOB包

     

    名稱 類型 描述
    DBMS_JOB.ISUBMIT 過程 提交一個新任務,用戶指定一個任務號
    DBMS_JOB.SUBMIT 過程 提交一個新任務,系統指定一個任務號
    DBMS_JOB.REMOVE 過程 從隊列中刪除一個已經存在的任務
    DBMS_JOB.CHANGE 過程 更改用戶設定的任務參數
    DBMS_JOB.WHAT 過程 更改PL/SQL任務定義
    DBMS_JOB.NEXT_DATE 過程 更改任務下一次運行時間
    DBMS_JOB.INTERVAL 過程 更改任務運行的時間間隔
    DBMS_JOB.BROKEN 過程 將任務掛起,不讓其重復運行
    DBMS_JOB.RUN 過程 在當前會話中立即執行任務
    DBMS_JOB.USER_EXPORT 過程 創建文字字符串,用于重新創建一個任務

    三、DBMS_JOB包參數

    DBMS_JOB包中所有的過程都有一組相同的公共參數,用于定義任務,任務的運行時間以及任務定時運行的時間間隔。這些公共任務定義參數見表2所示。

    表2 DBMS_JOB過程的公共參數

     

    名稱 類型 注釋
    Job BINARY_INTEGER 任務的唯一識別號
    What VARCHAR2 作為任務執行的PL/SQL代碼
    Next_date VARCHAR2 任務下一次運行的時間
    Interval VARCHAR2 日期表達式,用來計算下一次任務運行的時間

    下面我們來詳細討論這些參數的意義及用法。

    1、job

    參數job是一個整數,用來唯一地標示一個任務。該參數既可由用戶指定也可由系統自動賦予,這完全取決于提交任務時選用了那一個任務提交過程。DBMS_JOB.SUBMIT過程通過獲得序列SYS.JOBSEQ的下一個值來自動賦予一個任務號。該任務號是作為一個OUT參數返回的,所以調用者隨后可以識別出提交的任務。而DBMS_JOB.ISUBMIT過程則由調用者給任務指定一個識別號,這時候,任務號的唯一性就完全取決于調用者了。

    除了刪除或者重新提交任務,一般來說任務號是不能改變的。即使當數據庫被導出或者被導入這樣極端的情況,任務號也將被保留下來。所以在執行含有任務的數據的導入/導出操作時很可能會發生任務號沖突的現象。

    2、what

    what參數是一個可以轉化為合法PL/SQL調用的字符串,該調用將被任務隊列自動執行。在what參數中,如果使用文字字符串,則該字符串必須用單引號括起來。 what參數也可以使用包含我們所需要字符串值的VARCHAR2變量。實際的PL/SQL調用必須用分號隔開。在PL/SQL調用中如果要嵌入文字字符串,則必須使用兩個單引號。

    what參數的長度在Oracle7.3中限制在2000個字節以內,在Oracle 8.0以后,擴大到了4000個字節,這對于一般的應用已完全足夠。該參數的值一般情況下都是對一個PL/SQL存儲過程的調用。在實際應用中,盡管可以使用大匿名Pl/SQL塊,但建議大家最好不要這樣使用。還有一個實際經驗就是最好將存儲過程調用封裝在一個匿名塊中,這樣可以避免一些比較莫名錯誤的產生。我來舉一個例子,一般情況下,what參數可以這樣引用:

     

    what =>’my_procedure(parameter1);’

    但是比較安全的引用,應該這樣寫:

    what =>’begin my_procedure(parameter1); end;’

    任何時候,我們只要通過更改what參數就可以達到更改任務定義的目的。但是有一點需要注意,通過改變what參數來改變任務定義時,用戶當前的會話設置也被記錄下來并成為任務運行環境的一部分。如果當前會話設置和最初提交任務時的會話設置不同,就有可能改變任務的運行行為。意識到這個潛在的副作用是非常重要的,無論何時只要應用到任何DBMS_JOB過程中的what參數時就一定要確保會話設置的正確。

    3、next_date

    Next_date參數是用來調度任務隊列中該任務下一次運行的時間。這個參數對于DBMS_JOB.SUBMIT和DBMS_JOB.BROKEN這兩個過程確省為系統當前時間,也就是說任務將立即運行。

    當將一個任務的next_date參數賦值為null時,則該任務下一次運行的時間將被指定為4000年1月1日,也就是說該任務將永遠不再運行。在大多數情況下,這可能是我們不愿意看到的情形。但是,換一個角度來考慮,如果想在任務隊列中保留該任務而又不想讓其運行,將next_date設置為null卻是一個非常簡單的辦法。

    Next_date也可以設置為過去的一個時間。這里要注意,系統任務的執行順序是根據它們下一次的執行時間來確定的,于是將next_date參數設置回去就可以達到將該任務排在任務隊列前面的目的。這在任務隊列進程不能跟上將要執行的任務并且一個特定的任務需要盡快執行時是非常有用的。

    4、Interval

    Internal參數是一個表示Oracle合法日期表達式的字符串。這個日期字符串的值在每次任務被執行時算出,算出的日期表達式有兩種可能,要么是未來的一個時間要么就是null。這里要強調一點:很多開發者都沒有意識到next_date是在一個任務開始時算出的,而不是在任務成功完成時算出的。

    當任務成功完成時,系統通過更新任務隊列目錄表將前面算出的next_date值置為下一次任務要運行的時間。當由interval表達式算出next_date是null時,任務自動從任務隊列中移出,不會再繼續執行。因此,如果傳遞一個null值給interval參數,則該任務僅僅執行一次。

    通過給interval參數賦各種不同的值,可以設計出復雜運行時間計劃的任務。本文后面的“任務間隔和日期算法”將對interval表達式進行詳細討論,并給出一個實際有用interval表達式的例子。

    四、任務隊列架構和運行環境

    任務隊列在Oracle系統中其實是一個子系統,它具有自己特定的后臺過程和目錄表。該子系統設計的目的是為了能不在用戶干預下自動運行PL/SQL過程。

    1、任務隊列后臺過程

    任務隊列(SNP)后臺過程隨著Oracle實例的啟動而同時啟動。在文章前面已經談到初始化文件init.ora中的參數JOB_QUEUE_PROCESSES,用來設置有幾個隊列過程。這里設置了幾個過程,系統中就會有幾個SNP過程被啟動。JOB_QUEUE_PROCESSES這個參數,可以是0到36中的任何一個數,也就是說對于每個Oracle實例最多可以有36個SNP過程,也可以不支持隊列過程(=0)。在大多數操作系統中,SNP三個字母常作為過程名的一部分出現。如,在unix系統中,如果該Oracle實例名為ora8,有三個任務隊列過程,則這三個任務隊列過程名稱為:

     

    ora_ora8_snp0
    ora_ora8_snp1
    ora_ora8_snp2

    SNP后臺過程和其他的Oracle后臺過程的一個重要區別就是殺掉一個SNP過程不會影響到Oracle實例。當一個任務隊列過程失控或者消耗太多的資源時,就可以將其殺掉,當然這種情況不是經常遇到的。當一個SNP過程被殺掉或者失敗時,Oracle就自動啟動一個新的SNP過程來代替它。

    2、有關任務隊列的初始化參數

    初始化文件init.ora中的幾個參數控制著任務隊列后臺的運行,下面我們將對其進行詳細討論。

    (1)、JOB_QUEUE_INTERVAL

    任務隊列過程定期喚醒并檢查任務隊列目錄表是否有任務需要執行。參數JOB_QUEUE_INTERVAL決定SNP過程兩次檢查目錄表之間“休眠”多長時間(單位為秒)。間隔設的太小會造成由于SNP過程不斷檢查目錄表而導致不必要的系統吞吐量。相反如果間隔設得太大,SNP過程在特定的時間沒有被喚醒,那個時間的任務就不會能被運行。最佳的時間間隔設置要綜合考慮系統環境中不同的任務,60秒的確省設置可以滿足大多數的應用。

    (2)、JOB_QUEUE_KEEP_CONNECTIONS

    除了前面介紹的JOB_QUEUE_PROCESS和JOB_QUEUE_INTERVAL兩個參數以外,影響SNP后臺過程行為的第三個參數是JOB_QUEUE_KEEP_CONNECTIONS。當該參數為TRUE時,SNP過程在兩個任務的運行期間(也就是休眠期間),仍然和Oracle保持開放的連接。相反,如果為FALSE時,SNP過程將和數據庫斷開連接,當喚醒時刻到來時又重新連接并檢查任務隊列。

    選擇這兩種方法中的那一種,主要是考慮任務隊列的有效性和數據庫關閉方法。長期保持連接的效率比較高,但任務隊列會受到正常關閉數據庫的影響。這是因為任務隊列過程對于服務器管理器看來和一個普通用戶的過程沒有什么不同,而正常的關閉數據庫需要讓所有的用戶都斷開連接。而斷開連接和重新連接又給數據庫增加了負荷,但是可定期地使數據庫沒有可連接SNP過程,也就可以使數據庫正常關閉。對于有很多任務或者是任務重復執行的時間間隔較短(一個小時或者更少)的環境,一般將JOB_QUEUE_KEEP_CONNECTIOONS設置為TRUE,并修改關閉數據庫的腳本為立即關閉。對于嚴格要求采用正常方式關閉的數據庫或者是任務較少,重復間隔較長的環境,一般將該參數設置為FALSE。最好,要提醒一句,SNP過程僅在沒有任何任務運行時才斷開,這種情況下,那些需要比較長時間運行的任務SNP將在它們的生命周期內一致保持開放的連接,這就延遲了正常關閉數據庫的時間。

    3、建立運行環境

    當SNP過程喚醒時,它首先查看任務隊列目錄中所有的任務是否當前的時間超過了下一次運行的日期時間。SNP檢測到需要該時間立即執行的任務后,這些任務按照下一次執行日期的順序依次執行。當SNP過程開始執行一個任務時,其過程如下:

    1. 以任務所有者的用戶名開始一個新的數據庫會話。
    2. 當任務第一次提交或是最后一次被修改時,更改會話NLS設置和目前就緒的任務相匹配。
    3. 通過interval日期表達式和系統時間,計算下一次執行時間。
    4. 執行任務定義的PL/SQL
    5. 如果運行成功,任務的下一次執行日期(next_date)被更新,否則,失敗計數加1。
    6. 經過JOB_QUEUS_INTERVAL秒后,又到了另一個任務的運行時間,重復上面的過程。

    在前兩步中,SNP過程創建了一個模仿用戶運行任務定義的PL/SQL的會話環境。然而,這個模仿的運行環境并不是和用戶實際會話環境完全一樣,需要注意以下兩點:第一,在任務提交時任何可用的非確省角色都將在任務運行環境中不可用。因此,那些想從非確省角色中取得權限的任務不能提交,用戶確省角色的修改可以通過在任務未來運行期間動態修改來完成。第二,任何任務定義本身或者過程執行中需要的數據庫聯接都必須完全滿足遠程的用戶名和密碼。SNP過程不能在沒有顯式指明口令的情況下初始化一個遠程會話。顯然,SNP過程不能假定將本地用戶的口令作為遠程運行環境會話設置的一部分。

    提交的任務如果運行失敗會怎么樣呢?當任務運行失敗時,SNP過程在1分鐘后將再次試圖運行該任務。如果這次運行又失敗了,下一次嘗試將在2分鐘后進行,再下一次在4分鐘以后。任務隊列每次加倍重試間隔直到它超過了正常的運行間隔。在連續16次失敗后,任務就被標記為中斷的(broken),如果沒有用戶干預,任務隊列將不再重復執行。

    五、任務隊列字典表和視圖

    任務隊列中的任務信息可以通過表3所示的幾個字典視圖來查看,這些視圖是由CATJOBQ.sql腳本創建的。表4和5是各個視圖每個字段的含義。

    表3. 任務隊列中關于任務的數據字典視圖

     

    視圖名 描述
    DBA_JOBS 本數據庫中定義到任務隊列中的任務
    DBA_JOBS_RUNNING 目前正在運行的任務
    USER_JOBS 當前用戶擁有的任務

    表4. DBA_JOBS 和 USER_JOBS.字典視圖的字段含義

     

    字段(列) 類型 描述
    JOB NUMBER 任務的唯一標示號
    LOG_USER VARCHAR2(30) 提交任務的用戶
    PRIV_USER VARCHAR2(30) 賦予任務權限的用戶
    SCHEMA_USER VARCHAR2(30) 對任務作語法分析的用戶模式
    LAST_DATE DATE 最后一次成功運行任務的時間
    LAST_SEC VARCHAR2(8) 如HH24:MM:SS格式的last_date日期的小時,分鐘和秒
    THIS_DATE DATE 正在運行任務的開始時間,如果沒有運行任務則為null
    THIS_SEC VARCHAR2(8) 如HH24:MM:SS格式的this_date日期的小時,分鐘和秒
    NEXT_DATE DATE 下一次定時運行任務的時間
    NEXT_SEC VARCHAR2(8) 如HH24:MM:SS格式的next_date日期的小時,分鐘和秒
    TOTAL_TIME NUMBER 該任務運行所需要的總時間,單位為秒
    BROKEN VARCHAR2(1) 標志參數,Y標示任務中斷,以后不會運行
    INTERVAL VARCHAR2(200) 用于計算下一運行時間的表達式
    FAILURES NUMBER 任務運行連續沒有成功的次數
    WHAT VARCHAR2(2000) 執行任務的PL/SQL塊
    CURRENT_SESSION_LABEL RAW MLSLABEL 該任務的信任Oracle會話符
    CLEARANCE_HI RAW MLSLABEL 該任務可信任的Oracle最大間隙
    CLEARANCE_LO RAW MLSLABEL 該任務可信任的Oracle最小間隙
    NLS_ENV VARCHAR2(2000) 任務運行的NLS會話設置
    MISC_ENV RAW(32) 任務運行的其他一些會話參數

    表 5. 視圖DBA_JOBS_RUNNING的字段含義

     

    數據類型 描述
    SID NUMBER 目前正在運行任務的會話ID
    JOB NUMBER 任務的唯一標示符
    FAILURES NUMBER 連續不成功執行的累計次數
    LAST_DATE DATE 最后一次成功執行的日期
    LAST_SEC VARCHAR2(8) 如HH24:MM:SS格式的last_date日期的小時,分鐘和秒
    THIS_DATE DATE 目前正在運行任務的開始日期
    THIS_SEC VARCHAR2(8) 如HH24:MM:SS格式的this_date日期的小時,分鐘和秒

    六、任務重復運行間隔和間隔設計算法

    任務重復運行的時間間隔取決于interval參數中設置的日期表達式。下面就來詳細談談該如何設置interval參數才能準確滿足我們的任務需求。一般來講,對于一個任務的定時執行,有三種定時要求。

    1. 在一個特定的時間間隔后,重復運行該任務。
    2. 在特定的日期和時間運行任務。
    3. 任務成功完成后,下一次執行應該在一個特定的時間間隔之后。

    第一種調度任務需求的日期算法比較簡單,即'SYSDATE+n',這里n是一個以天為單位的時間間隔。表6給出了一些這種時間間隔設置的例子。

    表6 一些簡單的interval參數設置例子

     

    描述 Interval參數值
    每天運行一次 'SYSDATE + 1'
    每小時運行一次 'SYSDATE + 1/24'
    每10分鐘運行一次 'SYSDATE + 10/(60*24)'
    每30秒運行一次 'SYSDATE + 30/(60*24*60)'
    每隔一星期運行一次 'SYSDATE + 7'
    不再運行該任務并刪除它 NULL

    表6所示的任務間隔表達式不能保證任務的下一次運行時間在一個特定的日期或者時間,僅僅能夠指定一個任務兩次運行之間的時間間隔。例如,如果一個任務第一次運行是在凌晨12點,interval指定為'SYSDATE + 1',則該任務將被計劃在第二天的凌晨12點執行。但是,如果某用戶在下午4點手工(DBMS_JOB.RUN)執行了該任務,那么該任務將被重新定時到第二天的下午4點。還有一個可能的原因是如果數據庫關閉或者說任務隊列非常的忙以至于任務不能在計劃的那個時間點準時執行。在這種情況下,任務將試圖盡快運行,也就是說只要數據庫一打開或者是任務隊列不忙就開始執行,但是這時,運行時間已經從原來的提交時間漂移到了后來真正的運行時間。這種下一次運行時間的不斷“漂移”是采用簡單時間間隔表達式的典型特征。

    第二種調度任務需求相對于第一種就需要更復雜的時間間隔(interval)表達式,表7是一些要求在特定的時間運行任務的interval設置例子。

    表 7. 定時到特定日期或時間的任務例子

     

    描述 INTERVAL參數值
    每天午夜12點 'TRUNC(SYSDATE + 1)'
    每天早上8點30分 'TRUNC(SYSDATE + 1) + (8*60+30)/(24*60)'
    每星期二中午12點 'NEXT_DAY(TRUNC(SYSDATE ), ''TUESDAY'' ) + 12/24'
    每個月第一天的午夜12點 'TRUNC(LAST_DAY(SYSDATE ) + 1)'
    每個季度最后一天的晚上11點 'TRUNC(ADD_MONTHS(SYSDATE + 2/24, 3 ), 'Q' ) -1/24'
    每星期六和日早上6點10分 'TRUNC(LEAST(NEXT_DAY(SYSDATE, ''SATURDAY"), NEXT_DAY(SYSDATE, "SUNDAY"))) + (6×60+10)/(24×60)'

    第三種調度任務需求無論通過怎樣設置interval日期表達式也不能滿足要求。這時因為一個任務的下一次運行時間在任務開始時才計算,而在此時是不知道任務在何時結束的。遇到這種情況怎么辦呢?當然辦法肯定是有的,我們可以通過為任務隊列寫過程的辦法來實現。這里我只是簡單介紹以下,可以在前一個任務隊列執行的過程中,取得任務完成的系統時間,然后加上指定的時間間隔,拿這個時間來控制下一個要執行的任務。這里有一個前提條件,就是目前運行的任務本身必須要嚴格遵守自己的時間計劃。

    結論

    Oracle中的定時任務是在Oracle系統中是一個非常重要的子系統,運用得當,可以極大的提高我們的系統運行和維護能力。而Oracle數據復制的延遲事務隊列管理完全是基于Oracle的隊列任務,對其的深刻理解有助于我們更好地管理數據復制。


    posted @ 2009-08-26 10:30 鴻雁 閱讀(457) | 評論 (0)編輯 收藏

    IText使用PDF模板輸出報表的實踐(轉)

    本文所要用到的工具或jar主要有: Acrobat 8 這個主要用來制作PDF模板、eclipse這個看你喜歡咯(你用其他也行) 、 itext.jar、
    還有為了解決中文的輸出問題,需要多下載一個名為iTextAsian.jar的JAR包。這個包里面定義了與中文輸出相關的一些文件。
    好了,需要做的就是這些了,簡單的PDF生成這里就不再作介紹了,本文主要講解如何使用PDF模板。
    我們先來看看制作出來的效果:


    上圖表格上及表格中的數據是動態添加進去的,頁數為兩頁(為節約版面現只顯示一頁)
    兩頁都是用的同一模板的,
    1、 模板的制作:
    我主要使用的是Acrobat8.0,上面所用到的模板是由 周工作報告 模板修改而來的,如果想學習如何新建一個新的模板,大家可以參照下這里吧!
    http://lxy19791111.javaeye.com/blog/102848
    2、 取得每個表單域的名字
    模板制作好后,要插入數據首先就要知道需要插在模板中位置,
    Java代碼 復制代碼
    1.   //需要生成后的PDF    
    2. FileOutputStream fos = new FileOutputStream("c:/test/Pdf.pdf");    
    3.   //PDF模板路徑    
    4. String TemplatePDF ="c:/test/PdfTemplate.pdf";    
    5.        PdfReader reader = new PdfReader(TemplatePDF);      
    6. PdfStamper stamp = new PdfStamper(reader,fos);    
    7. AcroFields form = stamp.getAcroFields();    
    8. for (Iterator it = form.getFields().keySet().iterator(); it    
    9. .hasNext();) {    
    10. System.out.println(it.next());    
    11. }   

    這個是打印后的部分結果:

    我們只取后面那個命名就行,如"星期四[3]"
    當然,模板是你自己定義,文本域的命名你當然知道了,這里只是作個簡單介紹而已。
    3、下面是插入數據及PDF合并的代碼:
    Java代碼 復制代碼
    1. package com.golden.info.test;   
    2.   
    3. import java.io.ByteArrayOutputStream;   
    4. import java.io.FileNotFoundException;   
    5. import java.io.FileOutputStream;   
    6. import java.io.IOException;   
    7. import java.util.Date;   
    8.   
    9. import com.lowagie.text.Document;   
    10. import com.lowagie.text.DocumentException;   
    11. import com.lowagie.text.pdf.AcroFields;   
    12. import com.lowagie.text.pdf.PdfCopy;   
    13. import com.lowagie.text.pdf.PdfImportedPage;   
    14. import com.lowagie.text.pdf.PdfReader;   
    15. import com.lowagie.text.pdf.PdfStamper;   
    16. public class TestPdfTemplate {     
    17.     public static void main(String[] args) {   
    18.         try {   
    19.             int count = 8;// 總記錄數   
    20.             int pageCount = 4;// 每頁記錄數   
    21.             int index = 1// 表格序號   
    22.             int page = 0;// 總共頁數   
    23.             /** 主要控制總共的頁數*/  
    24.             if (count >= pageCount && count % pageCount == 0) {   
    25.                 page = count / pageCount;   
    26.             } else {   
    27.                 page = count / pageCount + 1;   
    28.             }   
    29.             String TemplatePDF = "c:/test/PdfTemplate.pdf";//設置模板路徑   
    30.             FileOutputStream fos = new FileOutputStream("c:/test/Pdf.pdf");//需要生成PDF   
    31.                
    32.             ByteArrayOutputStream baos[] = new ByteArrayOutputStream[page];//用于存儲每頁生成PDF流   
    33.             /** 向PDF模板中插入數據 */  
    34.             for (int item = 0; item < page; item++) {   
    35.                 baos[item] = new ByteArrayOutputStream();   
    36.                 PdfReader reader = new PdfReader(TemplatePDF);   
    37.                 PdfStamper stamp = new PdfStamper(reader, baos[item]);   
    38.                 AcroFields form = stamp.getAcroFields();   
    39.                 form.setField("DepartmnetNmae""藍飛");//插入的數據都為字符類型   
    40.                 form.setField("qq""252462807");                  
    41.                 form.setField("pageNumber""第" + (item + 1) + "頁,共" + page   
    42.                         + "頁");   
    43.                 if (count % pageCount != 0 && item == page - 1) {   
    44.                     System.out.println("====pageCount+" + pageCount + "=====");   
    45.                     pageCount = count % pageCount;   
    46.                 }   
    47.                 /**因為PDF中的表格其實是眾多的文本域組成,就是一個數組,所以把它循環出來就可以了*/  
    48.                 for (int j = 0; j < pageCount; j++) {   
    49.                     form.setField("ProjectTask[" + j + "]", index + "");   
    50.                     form.setField("星期一[" + j + "]""星期一[" + index + "]");   
    51.                     form.setField("星期二[" + j + "]""星期二[" + index + "]");   
    52.                     form.setField("星期三[" + j + "]""星期三[" + index + "]");   
    53.                     form.setField("星期四[" + j + "]""星期四[" + index + "]");   
    54.                     form.setField("星期五[" + j + "]""星期五[" + index + "]");   
    55.                     form.setField("星期六[" + j + "]""星期六[" + index + "]");   
    56.                     form.setField("星期日[" + j + "]""星期日[" + index + "]");   
    57.                     form.setField("意見[" + j + "]""同意[" + j + "]");   
    58.                     index++;   
    59.                 }   
    60.                 stamp.setFormFlattening(true); // 千萬不漏了這句啊, */   
    61.                 stamp.close();   
    62.             }   
    63.             Document doc = new Document();   
    64.             PdfCopy pdfCopy = new PdfCopy(doc, fos);   
    65.             doc.open();   
    66.             PdfImportedPage impPage = null;   
    67.             /**取出之前保存的每頁內容*/  
    68.             for (int i = 0; i < page; i++) {   
    69.                 impPage = pdfCopy.getImportedPage(new PdfReader(baos[i]   
    70.                         .toByteArray()), 1);   
    71.                 pdfCopy.addPage(impPage);   
    72.             }   
    73.             doc.close();//當文件拷貝  記得關閉doc   
    74.         } catch (FileNotFoundException e) {   
    75.             e.printStackTrace();   
    76.         } catch (IOException e) {   
    77.             e.printStackTrace();   
    78.         } catch (DocumentException e) {   
    79.             e.printStackTrace();   
    80.         }   
    81.   
    82.     }   
    83. }  


    至于,生于PDF后,想打印出來,只要調用以下代碼就行了
    Java代碼 復制代碼
    1.            
    2. try{                
    3. Executable ex = new Executable();          
    4.        ex.openDocument("c:/test/Pdf.pdf");              
    5.     ex.printDocument("c:/test/Pdf.pdf");   
    6.     }catch(IOException e){       
    7.     e.printStackTrace();         
    8.     }  

    到這里,運用上面的那些代碼,就完成了PDF模板輸出報表.
    (PDF模板、代碼跟運行結果在附件里)
    有錯誤之處請指正.
    也希望這篇文章可以幫到您.

    posted @ 2009-08-12 09:53 鴻雁 閱讀(4513) | 評論 (0)編輯 收藏

    利用 iText 實現 PDF 報表下載 (轉)

         摘要: 有個朋友的項目需要用到 PDF 報表下載,之前我只做過 Excel 的,相信再做一次 PDF 的下載一定很有趣吧。在網上找了一大圈,似乎 iText 比較符合我的要求,而且這個工具很早很早以前就有了,生命力很旺盛。進入 iText 的主頁(http://www.lowagie.com/iText/),發現作者很勤勞,最近2個月都有新版本發布。哪知道現在高興得太早了,一堆問題接踵而至。 下載倒...  閱讀全文

    posted @ 2009-08-12 09:50 鴻雁 閱讀(425) | 評論 (0)編輯 收藏

    iText JSP中生成PDF(入門)

    iText簡介

      iText是一個開放源碼的Java類庫,可以用來方便地生成PDF文件。大家通過訪問http://sourceforge.net/project/showfiles.php?group_id=15255&release_id=167948下載最新版本的類庫,下載完成之后會得到一個.jar包,把這個包加入JDK的classpath即可使用。如果生成的PDF文件中需要出現中文、日文、韓文字符,則還需要通過訪問http://itext.sourceforge.net/downloads/iTextAsian.jar下載iTextAsian.jar包。

      關于iText類庫的使用,http://www.lowagie.com/iText/tutorial/index.html有比較詳細的教程。該教程從入門開始,比較系統地介紹了在PDF文件中放入文字、圖片、表格等的方法和技巧。讀完這片教程,大致就可以做一些從簡單到復雜的PDF文件了。不過,試圖通過教程解決在生成PDF文件過程中遇到的所有困難無疑是一種奢望。所以,閱讀iText的api文檔顯得非常重要。讀者在下載類庫的同時,也可以下載類庫的文檔。

    可參考資料 :  

    http://dev.csdn.net/article/62/62119.shtm       http://myowndream.blog.com.cn/archives/2007/2089386.shtml
    http://tag.csdn.net/tag/itext.xml

    一  HelloWorld實例

    以下是上述教程中一個最簡單的例子,這個例子刻畫了通過iText生成PDF文件的一般程序框架。讀者只需要在document.open();和document.close();兩條語句中間加入自己希望放在PDF文件中的內容即可。該例子只在PDF文件中加了“Hello World“一行文字。

    Document document = new Document();

    try{
        PdfWriter.getInstance(document, new FileOutputStream ("Chap0101.pdf"));

        document.open();

        document.add(new Paragraph("Hello World"));
    }catch(DocumentException de){
         System.err.println(de.getMessage());
    }catch(IOException ioe){
         System.err.println(ioe.getMessage());
    }
     
    document.close();

    可以看到一個PDF文件的輸出,總共只需要5個步驟
    a.創建一個Document實例
      Document document = new Document();
    b.將Document實例和文件輸出流用PdfWriter類綁定在一起
      PdfWriter.getInstance(document,new FileOutputStream("HelloWorld.pdf"));
    c.打開文檔
      document.open();
    d.在文檔中添加文字
      document.add(new Paragraph("Hello World"));
    e.關閉文檔
      document.close();
    這樣5個步驟,就可以生成一個PDF文檔了。

    然而在PDF中指定文字、圖畫、表格的位置是一件非常麻煩的事情。除了不斷地在程序中修改位置、然后運行程序、生成PDF文件、觀察元素在PDF中的位置是否合理這樣的過程以外,似乎還沒有其它更好的方法。

    二。如何使用jsp、servlet輸出iText生成的pdf?
       如果每次都在服務端生成一個PDF文件給用戶,不僅麻煩,而且浪費服務器資源,最好的方法就是以二進制流的形式輸送到客戶端。
    1)JSP輸出:

    <%@ page import="java.io.*,java.awt.Color,com.lowagie.text.*,com.lowagie.text.pdf.*"%>
    <%
     response.setContentType( "application/pdf" );
     Document document = new Document();
     ByteArrayOutputStream buffer = new ByteArrayOutputStream();
     PdfWriter writer=PdfWriter.getInstance( document, buffer );

     document.open();

     document.add(new Paragraph("Hello World"));

     document.close();

     DataOutput output = new DataOutputStream( response.getOutputStream() );
     byte[] bytes = buffer.toByteArray();
     response.setContentLength(bytes.length);
     for( int i = 0; i < bytes.length; i++ ){
      output.writeByte( bytes[i] );
     }

    %>

    2)servlet輸出,稍微改造下就可以使用在struts中:

    import java.io.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    import com.lowagie.text.*;
    import com.lowagie.text.pdf.*;

    public void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException,ServletException{

      Document document = new Document(PageSize.A4, 36,36,36,36);
      ByteArrayOutputStream ba = new ByteArrayOutputStream();

      try{
       PdfWriter writer = PdfWriter.getInstance(document, ba);

       document.open();

       document.add(new Paragraph("Hello World"));
      }catch(DocumentException de){
       de.printStackTrace();
       System.err.println("A Document error:" +de.getMessage());
        }

      document.close();

      response.setContentType("application/pdf");
      response.setContentLength(ba.size());
      ServletOutputStream out = response.getOutputStream();
      ba.writeTo(out);
      out.flush();
    }

    三。如何輸出中文?
         首先需要下載iTextAsian.jar包,可以到iText的主站上下,ireport也是需要這個包的。然后定義中文字體:

        private static final Font getChineseFont() {
             Font FontChinese
    = null;
            
    try {
                 BaseFont bfChinese
    = BaseFont.createFont("STSong-Light",
                        
    "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
                 FontChinese
    = new Font(bfChinese, 12, Font.NORMAL);
             }
    catch (DocumentException de) {
                 System.err.println(de.getMessage());
             }
    catch (IOException ioe) {
                 System.err.println(ioe.getMessage());
             }
            
    return FontChinese;
         }


    我將產生中文字體封裝在方法內,自定義一個段落PDFParagraph繼承自Paragraph,默認使用中文字體:

    class PDFParagraph extends Paragraph {
            
    public PDFParagraph(String content) {
                
    super(content, getChineseFont());
             }
         }


    使用的時候就可以簡化了:

    Paragraph par = new PDFParagraph("你好");


    四。如何設置PDF橫向顯示和打印?

    Rectangle rectPageSize = new Rectangle(PageSize.A4);// 定義A4頁面大小
    rectPageSize = rectPageSize.rotate();// 加上這句可以實現A4頁面的橫置
    Document doc = new Document(rectPageSize,50,50,50,50);//4個參數,設置了頁面的4個邊距


    五。如何設置跨行和跨列?

    使用PdfPTable和PdfPCell 是沒辦法實現跨行的,只能跨列,要跨行使用com.lowagie.text.Table和com.lowagie.text.Cell類,Cell類有兩個方法:setRowspan()和setColspan()。

    六。如何設置單元格邊界寬度?

    Cell類的系列setBorderWidthXXXX()方法,比如setBorderWidthTop(),setBorderWidthRight()等

    七。如何設置表頭?
    希望每一頁都有表頭,可以通過設置表頭來實現。對于PdfPTable類來說,可以這樣設置:

    PdfPTable table = new PdfPTable(3);
    table.setHeaderRows(
    2); // 設置了頭兩行為表格頭


    而對于om.lowagie.text.Table類,需要在添加完所有表頭的單元格后加上一句代碼:

    table.endHeaders();


    八。如何設置列寬?

    Table table = new Table(8);
    float[] widths = { 0.10f, 0.15f, 0.21f, 0.22f, 0.08f, 0.08f, 0.10f,
                        
    0.06f };
    table.setWidths(widths);


    上面的代碼設置了一個有8列的表格,通過一個float數組設置列寬,這里是百分比。

    九。單元格內段落文字居中和換行?
    居中通過Cell類來設置,一開始我以為設置段落對齊就可以了,沒想到是需要設置單元格:

    cell.setHorizontalAlignment(Element.ALIGN_CENTER);



    轉義符\n實現。在我的這個應用中,因為數據庫取出的數據是為了顯示在html上的,所以有很多<br>標簽,可以使用正則表達式替換成"\n"

    "<br>1.測試<br>2.測試2".replaceAll("<br>|</br>","\n");


    十。如何顯示頁碼?
    復雜的頁碼顯示和水印添加,需要使用到PdfPageEventHelper、PdfTemplate等輔助類,具體的例子參見iText的文檔,如果只是為了簡單的顯示頁數,可以使用下面的代碼:

                 HeaderFooter footer = new HeaderFooter(new Phrase("頁碼:",getChineseFont()), true);
                 footer.setBorder(Rectangle.NO_BORDER);
                 document.setFooter(footer);
                 document.open();

    你可能注意到了,添加footer需要在document.open之前。

    posted @ 2009-08-12 09:48 鴻雁 閱讀(2336) | 評論 (0)編輯 收藏

    開發相關的重點技術介紹-轉貼

         摘要: 數據庫連接池的原理機制 數據庫連接池的原理機制 ...  閱讀全文

    posted @ 2009-05-15 10:32 鴻雁 閱讀(1367) | 評論 (0)編輯 收藏

    僅列出標題
    共18頁: First 上一頁 4 5 6 7 8 9 10 11 12 下一頁 Last 
    主站蜘蛛池模板: 国产精品成人免费综合| 亚洲一区无码精品色| 激情无码亚洲一区二区三区 | 久久精品国产亚洲AV高清热| 妻子5免费完整高清电视| 立即播放免费毛片一级| 久久亚洲精品成人综合| 亚洲熟妇无码八V在线播放 | 亚洲综合成人婷婷五月网址| 亚洲男人天堂2020| 成人免费黄色网址| 亚洲日本久久一区二区va| 亚洲熟女乱综合一区二区| 2021精品国产品免费观看| 亚洲嫩草影院久久精品| 国产伦精品一区二区三区免费迷 | 国产福利电影一区二区三区,亚洲国模精品一区| 久久久久久免费一区二区三区| 亚洲综合一区二区三区四区五区| 亚洲最大激情中文字幕| 思思99re66在线精品免费观看| 人妻在线日韩免费视频| mm1313亚洲国产精品无码试看 | 羞羞视频免费网站在线看| 亚洲永久在线观看| 亚洲AV成人精品网站在线播放| 国产大片线上免费看| 亚洲人成在线免费观看| 中国内地毛片免费高清| 国产精品亚洲精品久久精品 | 国产精品无码永久免费888| 亚洲日韩国产欧美一区二区三区| 亚洲av色福利天堂| 国产国拍亚洲精品福利| 四虎免费永久在线播放| 97人妻无码一区二区精品免费| A片在线免费观看| 久久不见久久见免费影院www日本| 亚洲精品无码人妻无码| 亚洲成aⅴ人片在线影院八| 四色在线精品免费观看|