發表於 程式分享

多個查詢及執行由同一組程式執行

想將多個查詢及產生檔案之程式碼(每組程式均有不同的運作邏輯),
以下是我規劃的架構(由spring4 + struts2 + hibernate5):

1.PNG

相關程式碼架構示意如下:
一、設定檔
1.struts.xml

...
 <action name="DTDayReport_*" class="com.xxx.action.DTDayReportAction" method="{1}">
 <result name="success">/ajax/DTDayReport.jsp</result>
 <result name="{1}" type="json">
 <param name="root">dataMap</param>
 </result>
 </action>
...

2.(enum) DayReport.java

public enum DayReport {
    SNP("SNP", "檔案一", "com.xxx.bean.DTRptXXX1"), 
    SNT("SNT", "檔案二", "com.xxx.bean.DTRptXXX2"), 
    SNT("SNT", "檔案三", "com.xxx.bean.DTRptXXX3");
    
    protected String id;
    protected String desc;
    protected String className;
    
    private DayReport(String id, String desc, String className) {
        this.id = id;
        this.desc = desc;
        this.className = className;
    }

    public String getId() {
        return id;
    }

    public String getDesc() {
        return desc;
    }

    public String getClassName() {
        return className;
    }
}

3.DTReportCol.java

public class DTReportCol {
    private String colId;
    private String colDesc;
    private String colType; //String, double , int, Date
    private int digit;      //顯示小數位數
    private String dateFmt; //Ex.yyyy-mm-dd
    private String codeType;

    public DTReportCol(String colId, String colDesc, String colType, int digit, String dateFmt) {
        this(colId, colDesc, colType, digit, dateFmt, "");
    }

    public DTReportCol(String colId, String colDesc, String colType, int digit, String dateFmt, String codeType) {
        super();
        this.colId = colId;
        this.colDesc = colDesc;
        this.colType = colType;
        this.digit = digit;
        this.dateFmt = dateFmt;
        this.codeType = codeType;
    }

    public String getColId() {
        return colId;
    }
    
    public void setColId(String colId) {
        this.colId = colId;
    }
    
    public String getColDesc() {
        return colDesc;
    }
    
    public void setColDesc(String colDesc) {
        this.colDesc = colDesc;
    }
    
    public String getColType() {
        return colType;
    }
    
    public void setColType(String colType) {
        this.colType = colType;
    }
    
    public int getDigit() {
        return digit;
    }
    
    public void setDigit(int digit) {
        this.digit = digit;
    }
    
    public String getDateFmt() {
        return dateFmt;
    }
    
    public void setDateFmt(String dateFmt) {
        this.dateFmt = dateFmt;
    }
    
    public String getCodeType() {
        return codeType;
    }

    public void setCodeType(String codeType) {
        this.codeType = codeType;
    }

    @Override
    public String toString() {
        return "DTReportCol [colId=" + colId + ", colDesc=" + colDesc + ", colType=" + colType + ", digit=" + digit
                + ", dateFmt=" + dateFmt + ", codeType=" + codeType + "]";
    }
}

4.(interface) DTRptInterface.java

import java.util.LinkedList;
import com.xxx.entity.DTReportCol;

public interface DTRptInterface {
    public abstract String retriveFileName();
    public abstract LinkedList retriveCols();
    public abstract boolean rerunByDate(String applyDate_in, String errorMsg, String modifyEmp);
    public abstract boolean removeByDate(String applyDate_in, String errorMsg, String modifyEmp);
}

二、bean檔
1.DTRptDayPK.java

import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Embeddable;

@Embeddable
public class DTRptDayPK implements Serializable {
    @Column(name = "applyDate")
    private Date applyDate;
    @Column(name = "rowIdx")
    private int rowIdx;
    
    public DTRptDayPK() {
        
    }

    public DTRptDayPK(Date applyDate, int rowIdx) {
        super();
        this.applyDate = applyDate;
        this.rowIdx = rowIdx;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((applyDate == null) ? 0 : applyDate.hashCode());
        result = prime * result + rowIdx;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        DTRptDayPK other = (DTRptDayPK) obj;
        if (applyDate == null) {
            if (other.applyDate != null)
                return false;
        } else if (!applyDate.equals(other.applyDate))
            return false;
        if (rowIdx != other.rowIdx)
            return false;
        return true;
    }

    public Date getApplyDate() {
        return applyDate;
    }

    public void setApplyDate(Date applyDate) {
        this.applyDate = applyDate;
    }

    public int getRowIdx() {
        return rowIdx;
    }

    public void setRowIdx(int rowIdx) {
        this.rowIdx = rowIdx;
    }

    @Override
    public String toString() {
        return "DTRptDayPK [applyDate=" + applyDate + ", rowIdx=" + rowIdx + "]";
    }
}

2.DTRptXXX1.java – 與DayReport.java配合設定,可n個

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
...

@Entity
@Table(name = "DTRptXXX1")
public class DTRptXXX1 implements Serializable, DTRptInterface {
    @EmbeddedId
    @AttributeOverrides({
        @AttributeOverride(
            name = "applyDate",
            column = @Column(name = "applyDate")),
        @AttributeOverride(
            name = "rowIdx",
            column = @Column(name = "rowIdx"))
    })
    protected DTRptXXX1PK dtRptDayPK;
    
    //請新增相關欄位
    ... 
    @Column(name = "modifyTime")
    private Date modifyTime;
    @Column(name = "modifyEmp")
    private String modifyEmp;
    
    public DTRptXXX1() {
        
    }

    public DTRptXXX1(DTRptDayPK dtRptDayPK, ... , Date modifyTime, String modifyEmp) {
        super();
        //請新增相關欄位
    ... 
        this.modifyTime = modifyTime;
        this.modifyEmp = modifyEmp;
    }

    public DTRptDayPK getDtRptDayPK() {
        return dtRptDayPK;
    }

    public void setDtRptDayPK(DTRptDayPK dtRptDayPK) {
        this.dtRptDayPK = dtRptDayPK;
    }

    public String getApplyComp() {
        return applyComp;
    }

    //請新增相關欄位之set及get function
    ... 
    
    public Date getModifyTime() {
        return modifyTime;
    }

    public void setModifyTime(Date modifyTime) {
        this.modifyTime = modifyTime;
    }

    public String getModifyEmp() {
        return modifyEmp;
    }

    public void setModifyEmp(String modifyEmp) {
        this.modifyEmp = modifyEmp;
    }
    
    @Override
    public String toString() {
        return "DTRptSNP [dtRptDayPK=" + dtRptDayPK + 
                ...
                ", modifyTime=" + modifyTime + ", modifyEmp=" + modifyEmp + "]";
    }
    
    @Override
    public String retriveFileName() {
        return "DTRptXXX1.txt";
    }
    
    @Override
    public LinkedList retriveCols() {
        LinkedList dtReportColList = new LinkedList<>();
        
        //請新增相關欄位
        ...
        dtReportColList.add(new DTReportCol("modifyTime", "修改時間", "Date", 0, "yyyy-mm-dd HH:mm:ss"));
        dtReportColList.add(new DTReportCol("modifyEmp", "修改人員", "String", 0, null));

        return dtReportColList;
    }

    @Override
    public boolean rerunByDate(String applyDate_in, String errorMsg, String modifyEmp) {
        DTServiceEntry dtServiceEntry = new DTServiceEntry();
        
        //1.條件判斷
        ...
        
        //2.清除舊資料
        boolean bRemoveOK = removeByDate(applyDate_in, errorMsg, modifyEmp);
        if (bRemoveOK == false) {
            errorMsg = "清除舊資料失敗" + errorMsg + ".";
            return false;
        }
        
        //3.取得資料
        ...
        
        //4.寫入資料庫
        ...
        
        //5.寫入檔案
        ...

        return bOK_modify;
    }

    @Override
    public boolean removeByDate(String applyDate_in, String errorMsg, String modifyEmp) {
        DTServiceEntry dtServiceEntry = new DTServiceEntry();
        Logger logger = LogManager.getLogger(this.getClass().getName());
        
        //1.清除舊資料
        ...
        
        //2.清除舊檔案
        ...
        
        return true;
    }
}

三、(View) DTDayReport.jsp
javascript呼叫後端action的主要程式碼示意如下

 //footable
 var myfootable = {
 first : true,
 rerun : function() {
 var kindVal = $('#s2_kind').find(':selected').val();
 var settleDateVal = $('#settleDate').val();
 if (kindVal.length <= 0 || settleDateVal.length <= 0) {
 if (myfootable.first == false) {
 $('#modal-body-msg').text("請輸入種類及日期.");
 $('#messageModal').modal('show');
 }
 myfootable.first = false;
 return;
 }
 myfootable.first = false;
 
 var formData = {kind : kindVal, settleDate : settleDateVal}; 
 $.ajax({
 url : 'DTDayReport_getJsonRerun.action',
 type: "POST",
 data : formData,
 dataType : 'json',
 success : myfootable.ajax_loaddata,
 error : function(xhr, statusText, error) { 
 alert("錯誤! 無法取得資料.");
 }
 });
 },
 query : function () {
 var kindVal = $('#s2_kind').find(':selected').val();
 var settleDateVal = $('#settleDate').val();
 if (kindVal.length <= 0 || settleDateVal.length <= 0) {
 if (myfootable.first == false) {
 $('#modal-body-msg').text("請輸入種類及日期.");
 $('#messageModal').modal('show');
 }
 myfootable.first = false;
 return;
 }
 myfootable.first = false;
 
 var formData = {kind : kindVal, settleDate : settleDateVal}; 
 $.ajax({
 url : 'DTDayReport_getJson.action',
 type: "POST",
 data : formData,
 dataType : 'json',
 success : myfootable.ajax_loaddata,
 error : function(xhr, statusText, error) { 
 alert("錯誤! 無法取得資料.");
 }
 });
 },
 ajax_loaddata : function(data) {
 $("#footable tbody tr").each(function(index, elem) {
 $(elem).remove();
 });
 
 $.each(data, function(index, item) {
 if (index == "result") {
 if (item.show == true || (item.success == false && myfootable.first == false)) {
 $('#modal-body-msg').text(item.message);
 $('#messageModal').modal('show');
 }
 } else if (index == 'TRANDATE') {
 $('.date-picker').datepicker('change', {dateFormat: 'yy-mm-dd', maxDate: item});
 } else if (index == 'dtRpt' && item != null) {
 $.each(item, function(index2, item2) { 
 var row = myfootable.create_table_row(item2);
 $('#footable tbody').append(row);
 });
 } else if (index == 'settleT2Date') {
 $('#settleT2Date').val(item);
 }
 });
 myfootable.first = false;
 $('#footable').trigger('footable_initialize');
 },
 create_table_row : function (item) {
 var row = '<tr>';
 $.each(reportColList, function(index_col, item_col) {
 var colId = ((item_col.colId == 'applyDate' || item_col.colId == 'rowIdx') 
 ? ('dtRptDayPK.' + item_col.colId) : item_col.colId);
 var sVal = eval('item.' + colId);
 
 //1.日期
 if (item_col.colType == 'Date') {
 sVal = sVal.replace('T',' ');
 if (item_col.dateFmt == 'yyyy-mm-dd')
 sVal = sVal.substring(0, 10);
 }
 //2.代碼mapping
 if (item_col.codeType != null && item_col.codeType.length > 0) {
 var mapObj = codeMap[item_col.codeType];
 if (mapObj !== undefined) {
 if (mapObj[sVal] !== undefined)
 sVal = sVal + '-' + mapObj[sVal];
 }
 }
 
 row += '<td data-value="' + sVal + '">' + sVal + '</td>';
 });
 
 row += '</tr>';
 return row;
 },
 downloadFile : function(e) { 
 e.preventDefault();
 
 var kindVal = $('#s2_kind').find(':selected').val();
 var settleDateVal = $('#settleDate').val();
 if (kindVal.length <= 0 || settleDateVal.length <= 0) {
 if (myfootable.first == false) {
 $('#modal-body-msg').text("請輸入種類及日期.");
 $('#messageModal').modal('show');
 }
 return;
 }
 
 var url = 'DTDayReport.action?kind=' + kindVal + '&type=Download&settleDate=' + settleDateVal;
 window.open(url, "_blank").focus();
 }
 }

 

四、(Action) DTDayReportAction.java

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
...

public class DTDayReportAction extends BaseAction {
    private static String rootPath = "DownloadPath_Ftp";
    
    //將被Struts2序列化為JSON字符串的對象  
    private Map<String, Object> dataMap = new LinkedHashMap<String, Object>();
    //Query
    private String kind;
    private String type;    //Download=下載檔案
    private String settleDate;
    
    public DTDayReportAction() {
        super();
        myPlatFormList.add(new UserPrivItem(PlatForm.DERIVTRADE.toString(), "DTDaySettle"));
    }
    /** 
     * Struts2序列化指定?性?,必?有??性的getter方法,??上,如果?有?性,而只有getter方法也是可以的 
     * @return 
     */  
    public Map<String, Object> getDataMap() {  
        return dataMap;  
    } 
    
    public void setDataMap(Map<String, Object> dataMap) {
        this.dataMap = dataMap;
    }
    
    //Query
    public String getKind() {
        return kind;
    }
    
    public void setKind(String kind) {
        this.kind = kind;
    }
    
    public String getType() {
        return type;
    }
    
    public void setType(String type) {
        this.type = type;
    }
    
    public String getSettleDate() {
        return settleDate;
    }
    
    public void setSettleDate(String settleDate) {
        this.settleDate = settleDate;
    }
    
    public String getJson() {
        boolean bSuccess = true;
        String message = "";
        
        dataMap.clear();
        
        //1.回覆結果 
        Map<String, Object> dataMessage = new LinkedHashMap<String, Object>();
        dataMessage.put("success", bSuccess);
        dataMessage.put("message", message);
        dataMessage.put("show", false);
        dataMap.put("result", dataMessage);
        
        //2.取得目前交易及前一結帳日
        String tranDate = ...
        request.setAttribute("TRANDATE", tranDate);
                
        //3.取得資料
        retriveData();
                
        return "getJson";
    }   
    
    public String getJsonRerun() {
        boolean bSuccess = false;
        String message = "";
        dataMap.clear();
        
        //1.取得欄位
        for (DayReport dayReport : DayReport.values()) {
            if (dayReport.getId().compareTo(kind) != 0)
               continue;
            
            final String className = dayReport.getClassName();
            Thread thread = new Thread(new Runnable() {
                public void run() {
                    try {
                        UserItem userItem = (UserItem) session.getAttribute("UserItem");
                        Class<?> dayReportClass = Class.forName(className); 
                        Constructor<?> constructor = dayReportClass.getDeclaredConstructor();
                        DTRptInterface obj = (DTRptInterface) constructor.newInstance();
                        Method method = dayReportClass.getMethod("rerunByDate", 
                                            new Class[] {String.class, String.class, String.class});
                            
                        String errorMsg = "";
                        boolean bRerunOK = (boolean) method.invoke(obj, settleDate, errorMsg, userItem.getUsername());
                        logger.info("bRerunOK: " + bRerunOK + ", errorMsg: " + errorMsg);
                    } catch (ClassNotFoundException e1) {
                        logger.error("kind=" + kind + " : ClassNotFoundException - " + e1.getMessage());
                    } catch (NoSuchMethodException e2) {
                        logger.error("kind=" + kind + " : : NoSuchMethodException - " + e2.getMessage());   
                    } catch (IllegalAccessException e3) {
                        logger.error("kind=" + kind + " : IllegalAccessException - " + e3.getMessage());
                    } catch (InvocationTargetException e4) {
                        logger.error("kind=" + kind + " : InvocationTargetException - " + e4.getMessage());
                        e4.printStackTrace();
                    } catch (InstantiationException e5) {
                        logger.error("kind=" + kind + " : InstantiationException - " + e5.getMessage());
                    }
                }
            });
            thread.start();
            try {
                thread.join(300 * 1000);
            } catch (InterruptedException e) {
                logger.error(e.getMessage());
            }

            bSuccess = true;
            break;
        }

        message = (bSuccess == true) ? "重新產出資料中,請確認." : "重新產出資料失敗,請確認.";
        
        //2.回傳結果 
        Map<String, Object> dataMessage = new LinkedHashMap<String, Object>();
        dataMessage.put("success", bSuccess);
        dataMessage.put("message", message);
        dataMessage.put("show", true);
        dataMap.put("result", dataMessage);
                
        //3.取得目前交易及前一日期
        String tranDate = ...
        request.setAttribute("TRANDATE", tranDate);
        
        //4.取得資料
        retriveData();
                
        return "getJsonRerun";
    }
    
    //取得清單
    private boolean retriveData() {
        if (kind.compareToIgnoreCase(DayReport.DTRptXXX1.getId()) == 0) {
            List dtRptXXX1List = ...
            dataMap.put("dtRpt", dtRptXXX1List);
        } else if (kind.compareToIgnoreCase(DayReport.DTRptXXX2.getId()) == 0) {
            ...
        } else
            return false;
        return true;
    }
    
    @Override
    public String execute() throws Exception {
        //下載檔案
        if (type != null && type.compareToIgnoreCase("Download") == 0) {
            String fileName = retriveFileName();
            if (fileName == null || fileName.trim().length() <= 0) {                 response.getWriter().println("Get File error");                 return NONE;            }                       String filePath = SysConfigUtil.getValue(application, rootPath) + File.separator +                      settleDate.replace("-", "") + File.separator + fileName;            logger.info("download filePath= " + filePath);                              FileInputStream fis = null;             try {               //1.開檔              fis = new FileInputStream(filePath);                                        //2.顯示檔案                byte[] buffer = new byte[1024];                 int len = 0;                String docFileName = java.net.URLEncoder.encode(fileName, "UTF-8");                 response.setHeader("Content-Disposition", "attachment;filename=".concat(docFileName));              String extension = DataUtil.getExtension(fileName);                 response.setContentType(getContentType(extension));                 OutputStream out = response.getOutputStream();              while ((len = fis.read(buffer)) > 0) {
                    out.write(buffer, 0, len);
                }
                out.close();
            } catch (IOException e) {
                logger.error(e.getMessage());
                response.getWriter().println("Get Image error");
            } finally {
                if (fis != null)
                    fis.close();
            }
                    
            return NONE;
        }
                
        //1.取得目前交易及前一結帳日
        String tranDate = ...
        request.setAttribute("TRANDATE", tranDate);
        
        //2.取得欄位
        for (DayReport dayReport : DayReport.values()) {            
            if (dayReport.getId().compareTo(kind) == 0) {
                try {
                    Class<?> dayReportClass = Class.forName(dayReport.getClassName()); 
                    Constructor<?> constructor = dayReportClass.getDeclaredConstructor();
                    DTRptInterface obj = (DTRptInterface) constructor.newInstance();
                    
                    Method method = dayReportClass.getMethod("retriveCols", new Class[] {});
                    LinkedList dtReportColList = (LinkedList) method.invoke(obj);

                    logger.info(dtReportColList);
                    request.setAttribute("dtReportColList", dtReportColList);
                } catch (ClassNotFoundException e1) {
                    logger.error("kind=" + kind + " : ClassNotFoundException - " + e1.getMessage());
                } catch (NoSuchMethodException e2) {
                    logger.error("kind=" + kind + " : : NoSuchMethodException - " + e2.getMessage());   
                } catch (IllegalAccessException e3) {
                    logger.error("kind=" + kind + " : IllegalAccessException - " + e3.getMessage());
                } catch (InvocationTargetException e4) {
                    logger.error("kind=" + kind + " : InvocationTargetException - " + e4.getMessage());
                } catch (InstantiationException e5) {
                    logger.error("kind=" + kind + " : InstantiationException - " + e5.getMessage());
                }
                
                break;
            }
        }
        
        return super.execute();
    }
    
    /**
     * 取得檔案名稱
     * @return
     */
    private String retriveFileName() {
        String fileName = null;
        for (DayReport dayReport : DayReport.values()) {
            if (dayReport.getId().compareTo(kind) != 0)
               continue;
            
            String className = dayReport.getClassName();            
            try {
                Class<?> dayReportClass = Class.forName(className); 
                Constructor<?> constructor = dayReportClass.getDeclaredConstructor();
                DTRptInterface obj = (DTRptInterface) constructor.newInstance();
                Method method = dayReportClass.getMethod("retriveFileName", new Class[] {});

                fileName = (String) method.invoke(obj);
                logger.info("fileName: " + fileName);
            } catch (ClassNotFoundException e1) {
                logger.error("kind=" + kind + " : ClassNotFoundException - " + e1.getStackTrace());
            } catch (NoSuchMethodException e2) {
                logger.error("kind=" + kind + " : : NoSuchMethodException - " + e2.getStackTrace());    
            } catch (IllegalAccessException e3) {
                logger.error("kind=" + kind + " : IllegalAccessException - " + e3.getStackTrace());
            } catch (InvocationTargetException e4) {
                logger.error("kind=" + kind + " : InvocationTargetException - " + e4.getStackTrace());
            } catch (InstantiationException e5) {
                logger.error("kind=" + kind + " : InstantiationException - " + e5.getStackTrace());
            }
            break;
        }
        
        return fileName;
    }
}

五、執行結果 : 每個查詢報表畫面類似如下

1.PNG

發表於 程式分享

java產生縮圖

因開發網站上大部份的圖均是透過管理介面讓管理者自行維運,
但有些圖檔過大,
故寫了一段產生縮圖的程式以免使用開啟網頁時塞爆頻寬。

1.指定圖檔寬度 : 傳入來源檔路徑(含檔名)、目的檔路徑(含檔名)、檔案副檔名、寬度

   public void change2SmallImg_w(String fromImgPath, String destImgPath, String imgType, int maxWidth) {
        try {
            File fiBig = new File(fromImgPath);
            File foSmall = new File(destImgPath);

            AffineTransform transform = new AffineTransform();
            BufferedImage bis = ImageIO.read(fiBig);
            //原来的高宽
            int w = bis.getWidth();
            int h = bis.getHeight();
            
            //等比例缩放 
            int nowWidth = maxWidth;
            int nowHeight = (nowWidth * h) / w;
            if (nowHeight > maxWidth) {
                nowHeight = maxWidth;
                nowWidth = (nowHeight * w) / h;
            }

            double sx = (double) nowWidth / w;
            double sy = (double) nowHeight / h;

            transform.setToScale(sx, sy);

            AffineTransformOp ato = new AffineTransformOp(transform, null);
            BufferedImage bid = new BufferedImage(nowWidth, nowHeight,
                    (imgType.compareToIgnoreCase("png") == 0) 
                        ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_3BYTE_BGR);
            ato.filter(bis, bid);
            
            ImageIO.write(bid, imgType, foSmall);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

2.指定圖檔高度 : 傳入來源檔路徑(含檔名)、目的檔路徑(含檔名)、檔案副檔名、高度

   public void change2SmallImg_h(String fromImgPath, String destImgPath, String imgType, int maxHeight) {
        try {
            File fiBig = new File(fromImgPath);
            File foSmall = new File(destImgPath);

            AffineTransform transform = new AffineTransform();
            BufferedImage bis = ImageIO.read(fiBig);
            //原来的高宽
            int w = bis.getWidth();
            int h = bis.getHeight();
            
            //等比例缩放 
            int nowHeight = maxHeight;
            int nowWidth = (nowHeight * w) / h;
            if (nowWidth > maxHeight) {
                nowWidth = maxHeight;
                nowHeight = (nowWidth * h) / w;
            }

            double sx = (double) nowWidth / w;
            double sy = (double) nowHeight / h;

            transform.setToScale(sx, sy);

            AffineTransformOp ato = new AffineTransformOp(transform, null);
            BufferedImage bid = new BufferedImage(nowWidth, nowHeight,
                    (imgType.compareToIgnoreCase("png") == 0) 
                        ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_3BYTE_BGR);
            ato.filter(bis, bid);
            
            ImageIO.write(bid, imgType, foSmall);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }