Showing posts with label Apache. Show all posts
Showing posts with label Apache. Show all posts

Friday, October 26, 2012

Exporting Data to Excel by Apache POI



Introduction

From official site:
The Apache POI Project's mission is to create and maintain Java APIs for manipulating various file formats based upon the Office Open XML standards (OOXML) and Microsoft's OLE 2 Compound Document format (OLE2). In short, you can read and write MS Excel files using Java. In addition, you can read and write MS Word and MS PowerPoint files using Java. Apache POI is your Java Excel solution (for Excel 97-2008).

This post do some practice of Apache POI, including set value to cell, style cell with Date format, Number format, align and font color, merge a range of cells, use Formula to calculate value, evaluate Formula result by FormulaEvaluator.

Required jar

poi-3.8-20120326.jar - http://poi.apache.org/download.html

The Program

POITest.java

Export some Fake data to excel file

package test.poi;

import java.io.FileOutputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Random;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;

public class POITest {
    private static SimpleDateFormat _shortDateformatter = new SimpleDateFormat("yyyy-MM-dd");
    // the style for Date column
    private static CellStyle _dateCellStyle;
    // the style for Money cells
    private static CellStyle _moneyCells;
    // the style for Money cells with negative value
    private static CellStyle _moneyCellsNegative;
    // evaluator to evaluate formula cell
    private static FormulaEvaluator _evaluator;

    public static void main (String[] args) {
        try {
            // create a new workbook
            Workbook wb = new HSSFWorkbook();
            // create a sheet with name "Balance"
            Sheet sheet = wb.createSheet("Balance");
            // get fake datas
            List<DateInOut> datas = generateFakeData();

            // add title row
            addTitle(sheet);
            // create cell styles as needed
            createCellStylesAndEvaluator(wb);
            // add datas
            addDatas(sheet, datas);
            
            // adjust column width
            autosizeColumns(sheet);

            // save workbook as .xls file
            saveBalanceReport(wb, "workbook.xls");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private static List<DateInOut> generateFakeData () throws ParseException {
        Calendar c = Calendar.getInstance();
        Random rand = new Random();
        List<DateInOut> datas = new ArrayList<DateInOut>();
        // set start date
        c.setTime(_shortDateformatter.parse("2012-01-01"));
        // generate fake datas within 200 days
        while (c.get(Calendar.DAY_OF_YEAR) < 200) {
            DateInOut dio = new DateInOut(c.getTime());
            // add 1-5 records
            for (int i = 0; i < (rand.nextInt(5) + 1); i++) {
                dio.addInOut(rand.nextInt(1000), rand.nextInt(1000));
            }
            datas.add(dio);
            // increase date
            c.add(Calendar.DAY_OF_YEAR, rand.nextInt(3) + 1);
        }
        return datas;
    }
    // add titles
    private static void addTitle (Sheet sheet) {
        // create row (3rd row)
        Row row = sheet.createRow(2);
        // add value to 3rd cell
        row.createCell(2).setCellValue("Ben Bai's Balance (not real)");
        // merge cells
        sheet.addMergedRegion(// first row (0-based), last row (0-based), first column (0-based), last column (0-based)
            new CellRangeAddress(2, 2, 2, 4));
        // go to 4th row
        row = sheet.createRow(3);
        // add values to cells
        row.createCell(1).setCellValue("Date");
        row.createCell(2).setCellValue("Income");
        row.createCell(3).setCellValue("Expenditure");
        row.createCell(4).setCellValue("Balance");
        row.createCell(6).setCellValue("Grand Total of Balance");
    }
    // create style for Date cell
    private static void createCellStylesAndEvaluator(Workbook wb) {
        // CreationHelper for create CellStyle
        CreationHelper createHelper = wb.getCreationHelper();
        _dateCellStyle = wb.createCellStyle();
        // add date format
        _dateCellStyle.setDataFormat(
            createHelper.createDataFormat().getFormat("yyyy-MM-dd"));
        // vertical align top
        _dateCellStyle.setVerticalAlignment(CellStyle.VERTICAL_TOP);

        // money style ( >= 0)
        _moneyCells = wb.createCellStyle();
        _moneyCells.setDataFormat(
                createHelper.createDataFormat().getFormat("$__##,##0.##"));
        // money style ( < 0)
        Font font = wb.createFont();
        font.setColor(Font.COLOR_RED);
        _moneyCellsNegative = wb.createCellStyle();
        _moneyCellsNegative.setDataFormat(
                createHelper.createDataFormat().getFormat("$__##,##0.##"));
        _moneyCellsNegative.setFont(font);

        _evaluator = wb.getCreationHelper().createFormulaEvaluator();
    }
    private static void addDatas (Sheet sheet, List<DateInOut> datas) {
        int rowIdx = 4; // start from 5th row
        Row firstDataRow = null;
        for (DateInOut dio : datas) {
            Date date = dio.getDate();
            List<InOut> inoutList = dio.getInOut();
            int size = inoutList.size();

            // merge "Date" column as needed
            sheet.addMergedRegion( // first row (0-based), last row (0-based), first column (0-based), last column (0-based)
                new CellRangeAddress(rowIdx, rowIdx + size - 1, 1, 1));
            Row row = sheet.createRow(rowIdx);
            // keep first row for later use
            if (firstDataRow == null)
                firstDataRow = row;
            // set date value
            Cell c = row.createCell(1);
            c.setCellStyle(_dateCellStyle);
            c.setCellValue(date);

            for (InOut io : inoutList) {
                // income and expenditure
                Cell cell = row.createCell(2);
                cell.setCellValue(io.getIncome());
                setNumericStyle(cell, false);

                cell = row.createCell(3);
                cell.setCellValue(io.getExpenditure());
                setNumericStyle(cell, false);

                // formula for calculate balance of one data row
                String formula = "C"+(rowIdx+1) + "-D"+(rowIdx+1);
                cell = row.createCell(4);
                cell.setCellType(HSSFCell.CELL_TYPE_FORMULA);
                cell.setCellFormula(formula);
                setNumericStyle(cell, true);
                
                // move to next row
                rowIdx++;
                row = sheet.createRow(rowIdx);
            }
            // add two empty column before next date
            rowIdx += 2;
        }
        // formula for calculate grand total of balance column
        String formula = "SUM(E5:E"+(rowIdx)+")";
        Cell gtb = firstDataRow.createCell(6);
        gtb.setCellType(HSSFCell.CELL_TYPE_FORMULA);
        gtb.setCellFormula(formula);
        setNumericStyle(gtb, true);
    }
    // set style to numeric cell
    private static void setNumericStyle (Cell cell, boolean isFormula) {
        double value = isFormula? getFormulaCellValue(cell) : cell.getNumericCellValue();
        if (value >= 0) {
            cell.setCellStyle(_moneyCells);
        } else {
            cell.setCellStyle(_moneyCellsNegative);
        }
    }
    // evaluate formula cell value
    private static double getFormulaCellValue (Cell cell) {
        _evaluator.evaluateFormulaCell(cell);
        return cell.getNumericCellValue();
    }
    // adjust column width
    private static void autosizeColumns (Sheet sheet) {
        // auto size not work with date
        sheet.setColumnWidth(1, 3000);
        sheet.autoSizeColumn(2);
        sheet.autoSizeColumn(3);
        sheet.autoSizeColumn(4);
        sheet.autoSizeColumn(6);
    }
    private static void saveBalanceReport (Workbook wb, String fileName) throws Exception {
        // create a new file
        FileOutputStream out = new FileOutputStream(fileName);
        // Write out the workbook
        wb.write(out);
        out.close();
    }
}
// one day with several income/expenditure pare
class DateInOut {
    private Date _date;
    private List<InOut> _inOut;
    public DateInOut (Date date) {
        _date = date;
        _inOut = new ArrayList<InOut>();
    }
    public void addInOut (int income, int expenditure) {
        _inOut.add(new InOut(income, expenditure));
    }

    public Date getDate () {
        return _date;
    }
    public List<InOut> getInOut () {
        return _inOut;
    }
}
// income/expenditure pare
class InOut {
    private int _income;
    private int _expenditure;
    public InOut (int income, int expenditure) {
        _income = income;
        _expenditure = expenditure;
    }

    public int getIncome () {
        return _income;
    }
    public int getExpenditure () {
        return _expenditure;
    }
}



The Result




References

Busy Developers' Guide to HSSF and XSSF Features
http://poi.apache.org/spreadsheet/quick-guide.html#WorkingWithFonts

Formula Evaluation
http://poi.apache.org/spreadsheet/eval.html

POI API Documentation
http://poi.apache.org/apidocs/overview-summary.html


Download

Full project at github
https://github.com/benbai123/JSP_Servlet_Practice/tree/master/Practice/JAVA/POI/POITest

Sunday, January 22, 2012

Integrate Tomcat with Apache HTTP Server: Forward JSP/Servlet Content to Tomcat

Usually we want serve static content or php by Apache, only serve JSP/Servlet content by Tomcat.
We can do this by several steps, described as follows:

Steps:

Step 1.
Get Apache HTTP Server:
go to http://httpd.apache.org/,
click from a mirror then download (I choose 2.2.21) and install


The document root of Apache HTTP Server is
APACHE_HOME/htdocs
(APACHE_HOME = [Install path]/Apache2.2)
You can change it by modify  APACHE_HOME /conf/httpd.conf

Create an icon named favicon.ico,
put it into APACHE_HOME/htdocs
You may need the png2ico to help this


Step 2.
Get Tomcat:
go to http://tomcat.apache.org/
click Tomcat 7.0 then download and install
(I just extract it)
then set TOMCAT_HOME Environment Variable

Step 3.
Copy htdocs/index.html and rename it to index.jsp,
put it at APACHE_HOME/htdocs/JEE/Test
(or put Test under TOMCAT_HOME/webapps if you skip Step 4.4)

currently it will show all html if you visit http://localhost/Test/index.jsp

Step 4.
Connect Apache HTTP Server and tomcat as follows:

Step 4.1.
Get mod_jk from http://www.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/windows/
I choose tomcat-connectors-1.2.32-windows-i386-httpd-2.2.x.zip
Extract it and find mod_jk.so in it
Put mod_jk.so into  APACHE_HOME /modules

Step 4.2.
Create workers.properties,
Put it into APACHE_HOME /conf
Edit it as below

# Define worker 'worker1'
worker.list=worker1

# Set properties for worker 'worker1' (ajp13)
worker.worker1.type=ajp13
worker.worker1.host=localhost
worker.worker1.port=8009

worker.worker1.cachesize=10
worker.worker1.cache_timeout=600
worker.worker1.socket_keepalive=1
worker.worker1.recycle_timeout=300

For more information of workers.properties, please refer to
http://tomcat.apache.org/connectors-doc/reference/workers.html

Step 4.3.
Create folder C:/var/log/httpd
Edit APACHE_HOME /conf/http.conf, append

# Load mod_jk module
LoadModule    jk_module  modules/mod_jk.so
# Where to find workers.properties
JkWorkersFile conf/workers.properties
# Where to put jk shared memory
JkShmFile     /var/log/httpd/mod_jk.shm
# Where to put jk logs
JkLogFile     /var/log/httpd/mod_jk.log
# Set the jk log level [debug/error/info]
JkLogLevel    info
# Select the timestamp log format
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
# Send servlet for context /Test to worker named worker1
JkMount  /Test/* worker1

This line JkMount /Test/* worker1 denotes forward the context path match /Test/* to Tomcat,
you can add multiple JkMount to define multiple path

Step 4.4.
This step should be skipped if you put Test under TOMCAT_HOME/webapps at Step 3
Edit TOMCAT_HOME/conf/server.xml

Change

<Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

to

<Host name="localhost"  appBase="APACHE_HOME\htdocs\JEE"
            unpackWARs="true" autoDeploy="true">

The Apache HTTP Server is connected to Tomcat now,
the only thing left to do is restart Apache HTTP Server and start Tomcat

Step 5.
Restart Apache HTTP Server:

Click the icon at System Tray


then click Apache2.2 -> Restart

Step 6.
Start Tomcat as a service,

At this point, make sure you have set the environment variables correctly,
for example:



Open cmd.exe as Administrator (Right click on cmd.exe -> Run as Administrator)
cd to TOMCAT_HOME/bin
Execute

service.bat install

NET START Tomcat7


Now you can visit http://localhost/Test/index.jsp and see your JSP page displayed correctly.

Download:
The resources can be downloaded from github
https://github.com/benbai123/JSP_Servlet_Practice/tree/master/Environment

References:
http://tomcat.apache.org/connectors-doc/webserver_howto/apache.html
http://tomcat.apache.org/connectors-doc/reference/workers.html
http://tomcat.apache.org/tomcat-4.1-doc/config/host.html
http://www.devside.net/guides/windows/tomcat