2022年12月12日 星期一

Spring Batch發生 EmptyResultDataAccessException 的排除

日前有個job Fail拋送EmptyResultDataAccessException,因為有組套設計故update會有多筆相符狀況,去爬了文找找發現是UPDATE的機制造成的。




解決方式: 使用 setAssertUpdates(boolean); 設定成FALSE後排除,不過使用上還是得依照Table Schema設計,若無多筆會符合情況下還是保留預設會比較安全。

2022年10月13日 星期四

HTML Page Convert to PDF

產製PDF在拉版時往往相對耗時,尤其是在有多頁的情況下相對搞工。測出來HTML FILE直轉PDF效果還不賴,做個備忘。

import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.html2pdf.resolver.font.DefaultFontProvider;
import com.itextpdf.io.font.FontProgram;
import com.itextpdf.io.font.FontProgramFactory;

public void ConvertPDF(String htmlPath ) {
String src = htmlPath;
try {
ConverterProperties properties = new ConverterProperties();
DefaultFontProvider fontProvider = new DefaultFontProvider();
FontProgram fontProgram;
try {
fontProgram = FontProgramFactory.createFont("c:\\windows\\fonts\\kaiu.TTF");
fontProvider.addFont(fontProgram);
properties.setFontProvider(fontProvider);
} catch (IOException e) {
System.out.println("creat base font erro:" + e );
}

HtmlConverter.convertToPdf(new File(src), new File(htmlPath.replace(".html", ".pdf")), properties);
} catch (Exception ex) {
System.out.println(ex);
}

<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>html2pdf</artifactId>
    <version>4.0.3</version>
</dependency>

後記:
2022/12/12 使用者反映轉出來的PDF有文字被裁切的問題,檢視後發現Bootstrap的CSS套用上拋了許多Exception出來,看來是HTML套版改用Bootstrap造成的問題,解決方式更新為 V4.0.4 後再檢視PDF成果已無被裁切之情事,結案。

iTextPDF add image

近期處理個需求需要在產出的PDF上面加上章戳圖,專案使用的是iTextPDF所以爬了些文找到了這方式,很順利的處理需求!! 做個備忘。

import java.net.URL;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.PdfContentByte;

document = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("D:\test.pdf"));
document.open();

//取得圖檔存放路徑
URL url = getClass().getProtectionDomain().getCodeSource().getLocation();
String spath = url.toString();
spath = spath.substring(0, spath.indexOf("WEB-INF"));
String imageFile = spath + "test.jpg";

PdfContentByte cb = writer.getDirectContent();
mage imgSoc = Image.getInstance(imageFile);
//設定大小
imgSoc.scaleToFit(60, 45);                     
//設定位置
imgSoc.setAbsolutePosition(490, 760); 
cb.addImage(imgSoc);

document.close();

補充說明:若原圖縮小到合適的SIZE後加入,印出來會相對模糊,因此改用scaleToFit來做縮圖處理,這樣列印的效果USER會比較滿意。

2022年10月6日 星期四

java read from DB2 column by Bolb type

近期配合保留原始資料將class資料轉json sting 存到DB的blob欄位內,底下是JAVA取值用的邏輯備忘下,試了許多方式就這樣最精簡也符合需要。

至於為什麼選擇blob而不用clob這個主要是考量若干資安掃描會去檢查cloumn data是否有踩紅線,改bytes array可以省去不必要的困擾,不然blob通常拿來存圖或是編譯後的檔案(PDF),這類json string存clob在DB tools上會較方便識別,就看各自的需要囉!!


source json data: 
bldata value is  new Gson().toJson(Variable.class).getBytes("utf-8")

Read

select bldata from table where length(bldata) > 4 with ur;

Blob blob = resultSet.getBlob("bldata"); 

byte[] bdata= blob.getBytes(1, (int) blob.length());

Variable.class Variables jsonStr = new Gson().fromJson(new String(bdata), Variable.class);

2022年9月21日 星期三

JAVA WEB專案中呼叫外部JAR執行取得回傳

 近日碰到了個需求,要整併外部的JAR到專案中,不過對方的JAR SIZE數十MB而自已所需要的只是裡面其中一個函式,故放入lib呼叫會造成專案封裝後的SIZE大增,不太OK~所以找到了ProcessBuilder這個好用的solution來,底下做個備忘囉!!

完工後的結果如下,效果如預期的方向呈現,OK的!

Process proc = null;

BufferedReader reader = null;
StringBuilder sbTravel = new StringBuilder();
try {
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("cmd", "/c", "java -jar d://hello.jar");
processBuilder.redirectErrorStream(true);
proc = processBuilder.start();

reader = new BufferedReader( new InputStreamReader(proc.getInputStream(), "Big5"));
String line;
while ((line = reader.readLine()) != null) {
if (StringUtils.isNotBlank(line)) sbTravel.append(line + "<br>");
}
int exitVal = proc.waitFor();
if (exitVal!=0) System.out.println("sbTravel:" + sbTravel + ",exitVal:" + exitVal);

} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (reader != null) reader.close();
if (proc != null) proc.getOutputStream().close();
} catch (IOException e) {
System.out.println("has IOException:" + e.toString());
}
}

補充:
間中也嘗試寫bat來執行,不過webSphere不給跑TOMCAT到是沒問題
Runtime.getRuntime().exec("cmd.exe /c start d:/hello.bat");

另外一個狀況是回傳值的取得,嘗試若干方法都沒能順利取值,間中也想過把console輸出寫成File來存取,但這方向容易有檔案被使用中卡住的exception(神奇的websphere),不然可以早些結案掉的。
Runtime.getRuntime().exec("java -jar d:/hello.jar > d:/bak/hello.TXT " );

後記:
2022-12-12 : 發行在WebSphere 9運行順利;但若改為WebSphere 8.5會拋送ssh handshake
exception,因此實作上等待伺服器更新緩不濟急因此用跳板方式轉到WebSphere 9的機器上
執行呼叫,缺點就是得多等個幾秒鐘。

2022年9月16日 星期五

options請求造成的兩次動作問題

 最近查一個bug從browser提交給AP,一個AJAX結果AP的console.log 看到兩次呼叫的紀錄,後來發現是多OPTIONS的請求,所以記錄下!!

從歷程看單一提交會有兩次的LOG,

在AP端同樣的也出現兩次紀錄


抓取req.Method會看到一次為OPTIONS;另一次為GET。所以增加IF判斷式排除OPTIONS觸發邏輯就可以下課了。


後記: 
用AP去實作WEB SERVER若content-type與發送端不一致,會觸發SocketException造成異常,此時務必跟對應的系統講好設定一樣。



CORS的問題也會造成困擾,從ajax提交設定中增加 crossDomain: true, 有幫助。

2022年7月22日 星期五

源碼掃描交手Part II

 年初因故將專案做了源碼掃描CHECKMARX,依照相關報告調整邏輯結果還是殘留了150左右的中高風險卡住了,近幾個月在上JAVA 11開發者的課程,補強了些JAVA的基本常識(=.= 做中學只能保證功能正確效率OK但語法是否能把該語言優勢發揮出來就難說了),再次挑戰雖然中高風險一就是150左右,但數據卻是顛倒過來,哈...

裡面的中、低風險有一堆是System.out.print() 、轉存檔案的風險,這主要是抓錯用的寫LOG或是不會被執行的項目,就先放著吧!! 等找到能騙過CHECKMARK說那段不會被跑到的寫法,應該就解決了。

專案管理是MAVRN、架構為MVC 若干的高風險都是在參數內容檢核時的風險,可以透過加Fitter時去觸發檢查XSS跟SQL Injection的邏輯! XssAndSqlHttpServletRequestWrapper 來複寫後再送入GOOGLE拿去檢索可以看到許多範例。

<filter>
  <description></description>
  <display-name>RequestFilter</display-name>
  <filter-name>RequestFilter</filter-name>
  <filter-class>ooo.xxx.filter.RequestFilter</filter-class>
  <inin-param>
<param-name>exclude</param-name>
<param-name>*.js,*.gif,*.jpg,*.jpeg,*.png,*.css,*.ico</param-name>
  </inin-param>
</filter>
<filter-mapping>
  <filter-name>SessionFilter</filter-name>
  <url-pattern>/*</url-pattern>
  <dispatcher>REQUEST</dispatcher>
</filter-mapping>

public class RequestFilter implements Filter {

@Override
public void init(FilterConfig filterConfig) throws ServletException {
  // Auto-generated method stub
}

@Override
public void doFilter(ServletRequest httpRequest, ServletResponse httpResponse, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) httpRequest;
HttpServletResponse response = (HttpServletResponse) httpResponse;

XssAndSqlHttpServletRequestWrapper xssRequest = new XssAndSqlHttpServletRequestWrapper((HttpServletRequest) request);
chain.doFilter(xssRequest, response);
}

@Override
public void destroy() {
  // Auto-generated method stub
}

}

CHECKMARK對於資料編碼使用會PASS的

JAVA:

用HtmlUtils.htmlEscape(value) ,之前用URLEncoder.encode(value) 會被無視。

如果邏輯使用StringUtils.isNotBlank() 判斷是否再處理,從報告上看也會被跳過,這時候就得先處理好null的情況後把StringUtils.isNotBlank()拿掉直接強制一定會落入檢核的method才能PASS。

JSP

用 value = org.apache.commons.text.StringEscapeUtils.escapeHtml4(value); 有用,非escapeHtml一就會報錯。


至於SQL Injection大概就是認關鍵字吧,把一些會誤殺的拿掉後多次嘗試即可! 這就不分享了畢竟每個專案環境跟用途不一樣,直接套用GG的機率頗高。

2022年5月18日 星期三

Eclipse無法自動編譯出class檔案

 最近幫位新手(非新人)解Bug說專案跑不起來,顯示

Spring專案啟動有Exception
org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find classs ...

看了下專案目錄bin下面沒東西,正常應該會有對應.javs的.class檔案,做個備忘囉~~小卡關以後萬一碰到可以參考。

Eclipse 的設定參考這篇網誌可以初步排除些設定上的問題,clean執行完後或是JDK移除重設定還怪怪的話,重啟Eclipse可以試試!! 不過這次碰上的個案不是這類的問題。

底下位置紅框處若有紅色X項時,要選取後選擇delete若沒清掉也無法Build,至於新手說他的另一個專案也有紅色X項但是可以build跟執行,=.= 這樣子喔...BJ4 







byte[] 與String 轉換中文亂碼備忘

姓名跟住址這類資料存取往往都會跟CharSet有關,如果某個環節沒弄好就是亂碼+破版來回報,做個備忘嚕!!

String CharSet = "UTF-8";
byte[] bytes_rowdata = s_addr.getBytes(CharSet );
String s_Addr = ArrayCopy2Str(bytes_rowdata, 0, 11, 20, CharSet );

/*
 * i_posstr: 相對起始位置
 * i_offset: 偏移位
 * len: 取的字元長度
 * CharSet: 字元編碼 
*/
private String ArrayCopy2Str(byte[] bytes_rowdata, int i_posstr, int i_offset, int len, String CharSet ) {

String s_val = "";
try {
vResult = new byte[len];
System.arraycopy( bytes_rowdata, i_posstr + i_offset, vResult, 0, len);
                        //還原字串也要設定字元編碼,如果沒給那一定機率會變亂碼
s_val = new String(vResult, CharSet);
} catch (Exception ex) {
System.out.println("ArrayCopy2Str has exception:" + ex.toString());
}

return s_val;
}

2022年5月17日 星期二

把JS ALERT變漂亮

 當系統開發運行趨於穩定後,使用者開始對UI/UX的需求就會趨向積極,恩恩...對單純的Programmer來說,美感永遠不是得優先強化的項目,當然嘔心瀝血做了好幾天更新上的版面,被吐槽到爆炸的評語帶來的挫折也不是一天兩天就能平復的,總之...依賴第三方套見是個不錯的選擇。

SWEETALERT2 可支援BootStrap是不錯的選擇,官網上的範例也很豐富大概常用的情境都有了,要更炫目的也有但使用者口味是會被養刁的,不要隨便做害人(舉某系統說他有位啥你沒有)害己(其他業管的系統為啥沒有)的決定。

取代alert();

Swal.fire("訊息","Hello world.","error");

取代comfirm();

Swal.fire({

  title: "警告",
  icon: "info", //warring(orange), primary(dark blue), info(blue), success(green), danger(red)
  html: "<font color='red'>查無OOOOO<br>請再次確認</font>",
  showCloseButton: false,
  showCancelButton: true,
  focusConfirm: false,
  confirmButtonText: "提交",
  cancelButtonText: "取消",
}).then((result) => {
  if (result.isConfirmed) {
  //Do something.;
  }

})

2022年4月20日 星期三

iTEXT QRCODE備忘

最近BarCode128 不夠用了,隨著硬體設備(掃描器)跟標籤機增購所以QRCode也上了時程,做個JAVA iTextPDF產製QRCODE的備忘文章。

import java.util.HashMap;
import java.util.Map;
import com.itextpdf.text.pdf.qrcode.EncodeHintType;
import com.itextpdf.text.pdf.qrcode.ErrorCorrectionLevel;
import com.itextpdf.text.pdf.BarcodeQRCode;

//QRCODE  
StringBuffer sb = new StringBuffer ();    
sb.append ("QRCODE內容");  
Map<EncodeHintType, Object> qrParam = new HashMap<EncodeHintType, Object> ();
qrParam.put ( EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M );
qrParam.put ( EncodeHintType.CHARACTER_SET, "UTF-8" );
//size_x, size_y 為QRCODE寬跟高
BarcodeQRCode qrcode = new BarcodeQRCode ( sb.toString (), size_x, size_y, qrParam );  
Image qrcode_img = qrcode.getImage();

InputStream input =  new FileInputStream("source.pdf");
OutputStream output= new FileOutputStream(new File("target.pdf"));

PdfReader reader = new PdfReader(input);           
PdfStamper stamper = new PdfStamper(reader, output);
PdfContentByte cb = stamper.getOverContent(1);

//x,y 放置在PDF內的座標位置
qrcode_img.setAbsolutePosition(x, y); 
cb.addImage(qrcode_img);

stamper.setFormFlattening(true);           
stamper.close();           
reader.close();