顯示具有 Java 標籤的文章。 顯示所有文章
顯示具有 Java 標籤的文章。 顯示所有文章

2024-08-21

Java Function

 研究 spring security jwt decode 設定過程看到. 

public void setJwsAlgorithmResolver(Function<ClientRegistration, JwsAlgorithm> jwsAlgorithmResolver) {

需要了解 Function<ClientRegistration, JwsAlgorithm> jwsAlgorithmResolver 的用法

理解後: 
Function 類是一個快速的 interface 讓你可以實作一個 object 傳進去. 
Function<T,R> 
T : method 傳入的參數 type
R : method 回傳的 type

簡單案例
        Function<String, Integer> lengthFunction = str -> str.length();
        Integer length = lengthFunction.apply("www.wdbyte.com");

2023-03-22

[java] Jackson 解析 Java 8 的 LocalDate 問題

 直接使用Jackson 解析 Java 8 之後提供的 LocalDate 會發生,Java 8 date/time type not supported by default. 

找到的解決方法. 

Java 8 LocalDate With Jackson In Spring Boot

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.9.3</version>
</dependency>


ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule()); 
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

2023-03-16

[spring] Spring boot application profiles and config properties include

 最近開發一個小的 sprint boot app,有使用到 db and amqp.  原先研究的方法是使用 profile 方式來區隔相關的環境使用的 config properties. 但是,後面還是遇到疊加與重複撰寫的問題。

研究一陣子,使用 application profile + include 方式來處裡這樣多變化的組合. 


第一步

首先,  application profile 其觀念是,每一次 spring boot 還是會讀取 application.proerpties ,再去讀取設定的 application-{profile}.properties。只是後面的會蓋掉前面的設定,所以差異化要做在後面那些 profile.  因此在 application.properties 只包含最簡單的. 設定 

application.properties

application.name=Gateweb Billing Agent
spring.profiles.active=local

application-local.properties

server.port=8181

spring.config.import=db-h2.properties,amqp-test.properties

application-test.properties

server.port=8080

spring.config.import=db-test.properties,amqp-test2.properties

第二步

將相關的資料 通通分開不同的設定檔. 

db-h2.properties

spring.sql.init.mode=always
spring.sql.init.platform=h2
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username=sa
spring.datasource.password=sa

##spring.datasource.schema=file:./test-data/schema-h2.sql
## Jpa Config
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
spring.jpa.properties.hibernate.show_sql=false
spring.jpa.show-sql=false 

amqp-test.properties

amqp.broker.host=cougar.rmq.cloudamqp.com
amqp.broker.vhost=xelvnewm
amqp.username=xelvnewm
amqp.password=SE6RHeTCJIf6E0KrxIOkDbdrEsYx82u2


db-test.properties

# Spring DB MySql
spring.sql.init.mode=never
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://test.mysql.database.azure.com:3306/test?useSSL=true&requireSSL=false
spring.datasource.username=test
spring.datasource.password=testpassword

# MySql Jpa Config
#spring.jpa.hibernate.ddl-auto=update
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.properties.hibernate.dialect.storage_engine=innodb
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.show-sql=true
spring.jpa.open-in-view=false

amqp-test2.properties

amqp.broker.host=cougar.rmq.cloudamqp.com
amqp.broker.vhost=xelvnewmsdsd
amqp.username=xelvnewmsdsd
amqp.password=SE6RHeTCJIf6E

第三步

修改 build.gradle 新增 相關 bootRun task 

tasks.register('bootRunLocal') {
dependsOn 'bootRun'
bootRun.systemProperty('spring.profiles.active', 'local')
}

tasks.register('bootRunTest') {
dependsOn 'bootRun'
bootRun.systemProperty('spring.profiles.active', 'test')
}





2023-02-02

[gradle] 讓多個 project 可以共用相同的 resources

 最近開始把開發專案做不同module 的拆分,但在做測試時需要把相同的 test data 分享給不同的 module 使用。 一開始先選擇在每個module 底下維護自己的一套相關設定,當 module 多的時候發現這樣維護太累了. 

接下來透過共用外部一個folder 來使用,所以先選擇會動的方式,使用絕對路徑方式來處理相關的 resource file. 


最終版本,透過 gradle config 來達到這樣一個作法. 看了很多做法,也試試看是否可以使用. 最終使用 新增一行gradle script 來解決. 


sourceSets.test.resources.srcDir file("$rootDir/$commonFolder")

2022-12-20

[java] android studio 安裝 lombok plugin

 android studio 無法從 markplace 安裝 lombok plugin. 

 找到下面這一篇,手動下載 plugin zip , 並放到 android studio/plugin 目錄. 

但需要修正的地方, mac 安裝 android studio 位置不一樣. 要改在....

/Applications/Android Studio.app/Contents/plugins


參考資料

https://stackoverflow.com/questions/70900954/cannot-find-lombok-plugin-in-android-studio-2021-1-1-build-of-2022

2020-03-26

[java] 使用Lombok 在 IntelliJ

需要寫某些Service的SDK,參考相關的開發後,有需要用到 Builder Pattern。
lombok 可以提供builder 的方式,一開始用 IntelliJ 去開發,在Test Code 中怎樣都沒有辦法產生相關的 builder() method. 找了幾個相關的資料,下面這一個是可以解決IDE 的問題.

 https://ask.xiaolee.net/questions/1149362
其中 去安裝 lombok plugin 可以解決我的問題.

2013-06-05

Samba client 設定 file path , 需多增加一個$

最近需要使用到 samba client 連結上 MS 的網路芳鄰. 測試的網路芳鄰有兩種.
1. 自己Windows 開放目錄給其他人.  private_server
2. Data Server 開放給所有人的 目錄分享.  public_server

MacOS 測試

1.測試自己開的 smb://private_server/share  , 順利連接上
2 測試 DataServer smb://public_server/share, 無法連上

jCIFS 測試

1.測試 DataServer smb://public_server/share  無法連上.

 
andSmb App 測試

1. 測試 smb://public_server 可以連接上
2. 點選 share 目錄, 無法連接上.
3. 看到還有一個 share$ 目錄, 試試看, 連接上了. 

回頭測試 MacOS and jCIFS

1. macos 測試 smb://public_server/share$ 連接上了
2. jCIFS 測試 smb://public_server/share$ 連接上了.

結論

1.自已開的Window share Folder 採用一般的 file 就可以
2.Server 分享有權限管制, 要加上file$

2012-04-16

[Linux] Linux and Java Broadcast connection

最近寫 Linux server and Java Client .  之前, 都只能用 192.168.1.255 的方式.
目前改寫測試, 已經可以運用 255.255.255.255.
Linux Server : 可以直接註冊  255.255.255.255:9999 bind
Java Client :  DatagramSocket  需指定會傳送 Broadcast 的 IP.
與上一版的差別, 在於 JavaClient 需要指定 出口 IP

2012-03-24

char on Arm-Linux

最近在寫 Linux socket Server. 需要從  Java 傳送 資料到Linux Server .
Linux 用 *char 來接收. Java 得用byte  方式傳送才有辦法一致.
當開發環境在 pc Linux 時, default is signed char.
當程式轉換到 Arm-Linux 時, 他卻是跑出 unsigned char.
所以, 當你需要 signed char on Arm-Linux , 就是直接宣告為 signed char.
否則, Arm-Linux default char is unsigned char.

2011-07-14

[Java] 設定 JVM 起始的 Timezone

原因
在目前的工作裡頭, 需要協助管理美國分公司的Server. 但是, 要管理又只能偷偷進去美國Server偷偷作. 所以這一次需要換掉 Jboss Server, 我打算將美國的Server 轉回台灣Server. 因為這件事情只能偷偷作, 所以得在台灣模擬美國的環境. 就碰到 時區問題, 因為美國那邊堅持在塞資料進他們家的Database 要用他們的 時區. 所以當 Jboss Server 跑在台灣Server 時間就會是台灣的時間. 所以必須想辦法, 變動 台灣Server 的時區.
解法
只好從JVM 啟動時入手. 查過資料, java -Duser.timezone 就可以設定 啟動時的時區.
所以在 Jboss 中, 啟動時 多加入 -Duser.timezone 就可以. 要特別注, 網路上有說法要用 -Duser.timezoe='xxx'. 這樣會無法使用, 得使用-Duser.timezone=xxx 就可以.
下面的設定會有日光節約時間

-Duser.timezone=America/Los_Angeles

這樣就沒有節約時間

-Duser.timezone=GMT-0800

2011-04-08

共用EJB - Remote JNDI 篇

先前寫了 Remote篇, 就開始把 EJB 都作成 EJB3 Module 方式去 deploy 在 Jboss Server上面. 經過一段時間的驗正, 都還蠻順利的. 不過, 還是出問題了.
先前把一堆共用的 java class 放在同一個 jar 中, 讓其他 EJB 共用這一個 jar.  就出現一個怪問題了,  EJB_A 包涵 jar , EJB_B 也包涵 jar. 先將 EJB_A deploy上去成功, 在 將 EJB_B deploy 時就會出現 duplicat class 的Exception. 反過來, EJB_B 先放, 在放 EJB_A 就不會出現問題. 但是系統是會越來越大的, 不會只有兩個 EJB . 所以, 問題是要解決的.
所以想到的方式是, 是不是 可以透過 ear 包裝方式, 解決這一個問題.  但是, 之前用ear deploy 在 JNDI Tree 中, 都會出現 ear project name . 這樣還是沒辦法解決最原始的問題 , 就是要透過 JNDI Name  找出相關的 service 來用壓.
就在看著 source code時,  噹噹靈感來了. 在原來的code 中.
@Stateless(name = "edi/service/Workflow")
就想說試試看 多一定義 會不會有不一樣. 把 code 改成
@Stateless(name = "edi/service/Workflow", mappedName="/edi/service/Workflow") 

實驗出爐....
這樣改比原來的還要好, 在 JNDI Tree 中 直接出現 edi/service/Workflow . 不用像之前的版本一樣在多加一個 remote. 所以這樣的方法會比較好, 可以避免多重問題.

2010-12-29

共用EJB - Remote 篇

先前寫了共用EJB - Local 篇. 後來,要把他運用在同一個container Server , 不同的EJB3 或者 web 上時, 發現他根本不能work . 會一直跑出 Wrong target Eroror message. 研究了一下, 發現應該是不同的 EJB package 不能共用 local ,要用 remote 的方式.

另外就是, 如果你是不同的EJB package 採用 resource inject 方式, 那如果被引用的 EJB shutdown. 引用別人的 EJB or web 在 jboss 6 上面會掛掉, 得重新啟動才有辦法繼續運作. 所以. 建議方式是採用 InitialContext 方式去 引用外部的 EJB resource, 不然一天到晚你要記得去 restart .


在 Session Bean 部份的寫法


package test;

import javax.ejb.Stateless;

@Stateless(name="test/TestSessionBean")
public class TestSessionBean implements TestSessionBeanRLocal,TestSessionBeanRemote {

@Override
public void test() {
System.out.println("Hello Test Bean");
}

}


引用 共用 SessionBean 的寫法(Resource Injection)


package test;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import test.TestSessionBeanLocal;


@Stateless
public class TestBean implements TestBeanLocal {

@EJB(mappedName = "test/TestSessionBean/remote")
TestSessionBeanRemote testBean;

@Override
public void testBean() {
testBean.test();
}
}



上面標注紅色字體部份, 就是在jboss 下面可以正常運做的 code.
主要在 引用共用session bean 那邊的設定, 需要多加一個 /remote , 這是跟local 不一樣的地方.



引用 共用 SessionBean 的寫法(jndi lookup)


package test;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import test.TestSessionBeanLocal;
import javax.naming.InitialContext;

@Stateless
public class TestBean implements TestBeanLocal {

TestSessionBeanRemote testBean;

@Override
public void testBean() {
InitialContext ctx = new InitialContext();
testBean = (TestSessionBeanRemote)ctx.lookup("
test/TestSessionBean/remote");
testBean.test();
}
}

2010-10-28

Eclipse Link JPA on jboss

之前使用 jpa + jta 的時候, 使用到transaction commit 時, 沒有詳細去注意各個 jpa 時做的問題. 但是, 今天就遇到一個問題, 讓目前開發的時候, 如果針對同一個 table 要作資料更新, 才發現不一樣的 jpa 實做會有不一樣的結果.
同一份 EJB 的程式放在 Jboss 6.0 and weblogic 會有不一樣的結果. Jboss 會出現 rollback , 但是 weblogic 不會. 這下又有趣了.
還好, 從Exception 中我看到 jboss 是 org.hibernate 的Exception. 就讓我想到會不會是 jpa 實做的不同導致的. 果然, weblogic 不是採用 hibernate jpa , 是用 eclipse link jpa.
有了這一條線索, 就上網找資料如何讓 jboss 可以採用 eclipse link jpa. EclipseLink/Examples/JPA/JBoss Web Tutorial 這一篇有講到, 但是有一些不一樣.
整個做完以後, eclipselink 做的 有些地方比 hibernate 好.

作法
  1. 下載 eclipse link jpa
  2. 將 eclipselink.jar 放入 ${jboss_home}/server/${server_name}/lib (這邊個上面的文章放的地方不太一樣, 因為我放過 有問題)
  3. 修改
    persistence.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
    <persistence-unit name="DefaultDB" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>java:jdbc/DefaultDB</jta-data-source>
    <class>entity.testBean</class>
    <properties>
    <property name="eclipselink.target-server" value="JBoss"/>
    <property name="eclipselink.target-database" value="Oracle"/>
    </properties>
    </persistence-unit>
    </persistence>


provider 之前沒有設定 jboss 會直接抓 container server 的, 現在在這邊指定就可以讓jpa 使用設定的 jpa implements.

eclipselink.target-server 這一個設定值一定要做, 尤其在 jboss server上面, 前沒有做的時候. 一直跑出 No Transaction is currently. 應該是沒有設定 eclipselink 沒有辦法去抓到 jboss xa manager.
eclipselink.target-database 這一個建議要設定, 開始的時候使用Oracle 沒有設定是沒有問題的. 但是轉成 MSSQL 後, 就會有問題. 設定值參考 Sun GlassFish Enterprise Server v3 Prelude Developer's Guide , Chapter 6 Using the Java Persistence API -Specifying the Database 裡頭有各家 DB 的設定值.



詳細問題
在Oracle 設計Table 的時候, 除了會設定primary key 以外, 還可針對欄位作一些 check rule. 現在遇到問題就是, 當我要作一筆 Transaction, 所做的動作為 :
  1. 找尋就有資料是否有存在的組合.
  2. 有符合的資料, 就將資料欄位 isAtvice 從 true 改為 false.
  3. Insert 新的資料進去
在weblogic 中, 這樣一個transaction 是可以完成的. 但是轉換到 jboss 時, 會出現 check rule Exception.
問題後來發現就是出在 hibernate 在處理 transaction 的方法, 跟 eclipselink 處理不同, 所以相同的DB 會出現不同的結果.

參考文獻
  1. Integrating EclipseLink with an Application Server (ELUG)
  2. EclipseLink/Examples/JPA/JBoss Web Tutorial
  3. Sun GlassFish Enterprise Server v3 Prelude Developer's Guide , Chapter 6 Using the Java Persistence API -Specifying the Database

2010-10-25

SQLite on SQuirrel

為了要處理 firefox 資料肥大的問題, 得進去firefox 的place.sqlite看一下.
找了一下, 看有沒有 可以在 squirrel上面可以直接 使用的方法.

最簡單就是找到 sqlite jdbc driver 裝上去.
下載
1. SQLiteJDBC

設定

  1. Click on the Drivers tab on the left, and add a new driver

      Name : SQLite Driver
      Example URL : jdbc:sqlite://
      Website URL: http://www.zentus.com/sqlitejdbc/


  2. Click on the Extra Class Path tab. Click the Add button, then navigate and select the sqlitejdbc jar file.
  3. Click List Drivers and org.sqlite.JDBC will appear in the Class Name field.
  4. Click Button[Ok].

2010-09-29

log4j on Jboss

最近把 project 到了一個段落, 要回來處理一下 log 的問題.
看了很多篇文章, 都發現jboss 上面 要跑含 log4j 的code 像是會有點問題. 看很多網頁, 沒有真的去試試看還不知道會是怎樣. 是了一兩個在 jboss 5.0 jboss 4.0 的解決方案, 好像不是適用於 jboss 6.0 M3.
就硬著把 ${JBOSS_HOME}/server/default/deply 看一輪, 發現到有一個檔案 jboss-logging.xml 裡面有用到jboss 自己的 log , 還有幾個appended 是用 log4j. 想說那就來試試看吧.
想說不用太複雜可以跑就好, 就找 ${JBOSS_HOME}/server/standard/ 來改好了. 要把log4j.jar 放見 ${JBOSS_HOME}/server/stardand/lib 裡面, 發現哇勒 裡面已經有放 一個log4j.jar. 跟在default裡面的lib 不一樣, default/lib 裡面一個東西都沒有, 這邊居然有. 簡單寫一個 web app, 用到log4j 去放.

修改 ${JBOSS_HOME}/server/stardand/deploy/jboss-logging.xml
1. 我是選用 他原有的 FILE 下去修改 , 新增到 檔案裡頭

<size-rotating-file-handler
file-name="${jboss.server.log.dir}/app.log"
name="FILE-APP"
autoflush="true"
append="true"
rotate-size="500k"
max-backup-index="5">

<error-manager>
<only-once/>
</error-manager>

<formatter>
<pattern-formatter pattern="%d %-5p [%c] (%t) %m%n"/>
</formatter>
</size-rotating-file-handler>

2. 新增相對的 logger

<logger category="test.logger">
<level name="DEBUG"/>
<handlers>
<handler-ref name="CONSOLE"/>
<handler-ref name="FILE-APP"/>
</handlers>
</logger>

3. 撰寫測試 log4j 的code

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;

@WebServlet(name = "Test", urlPatterns = {"/Test"})
public class Test extends HttpServlet {

private static Logger log = Logger.getLogger("test.logger");

/**
* Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
log.debug("Log Debug");
log.info("Log Info");
} finally {
out.close();
}
}

// <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the sign on the left to edit the code.">
/**
* Handles the HTTP <code>GET</code> method.
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

/**
* Handles the HTTP <code>POST</code> method.
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

/**
* Returns a short description of the servlet.
* @return a String containing servlet description
*/
@Override
public String getServletInfo() {
return "Short description";
}// </editor-fold>
}



測試一下, 發現很正常, 可以在jboss container 下面, 正常的使用.不用像 jboss docs 裡面寫得, 得用 jboss 包過得 Logger 下去做事情.

ps: 測試的過程中, 我將 standard/lib/log4j.jar copy to default/lib/ 來使用

2010-08-03

JAXB : Java object to XML without XML Schema

在 jdk 6.0 上面 已經內建 JAXB. 所以直接使用就可以.
研究了一陣子, 看了很多文件. 都大概需要使用xml schema 來產生 java to xml.
不過今天看到一個文章 Generate an XML Document from an Object Model with JAXB 2裡頭有範例, 可以不用使用 XML schema. 就來試試看摟.

開發兩個 Enity Bean(Person.java, Address.java) , 還有一個測試轉換的 Test Code(PersonTest.java).
1. 在 Person 中, 會包涵 Address. 所以在 Person 定義 @XmlRootElement. 這樣Address 也會自動被轉成xml.
2. Address 作一個設定, 原本應該要產生 zipcode tag, 如果想要換成別的. 必須先定義@XmlAccessorType(XmlAccessType.FIELD), 然後在 zipcode field在定義@XmlElement(name = "zip") 這樣轉換出來的address tag 會包涵zip tag 不會是 zipcode tag.




Person.java

package jaxbtest;

import javax.xml.bind.annotation.XmlRootElement;

/**
*
* @author longtai
*/
@XmlRootElement
public class Person {
private String name;
private String email;
private Address address;

/**
* @return the name
*/
public String getName() {
return name;
}

/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}

/**
* @return the email
*/
public String getEmail() {
return email;
}

/**
* @param email the email to set
*/
public void setEmail(String email) {
this.email = email;
}

/**
* @return the address
*/
public Address getAddress() {
return address;
}

/**
* @param address the address to set
*/
public void setAddress(Address address) {
this.address = address;
}

}


Address.java

package jaxbtest;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;

/**
*
* @author longtai
*/
@XmlAccessorType(XmlAccessType.FIELD)
public class Address {
private String address;
@XmlElement(name = "zip")
private String zipcode;

/**
* @return the address
*/
public String getAddress() {
return address;
}

/**
* @param address the address to set
*/
public void setAddress(String address) {
this.address = address;
}

/**
* @return the zipcode
*/
public String getZipcode() {
return zipcode;
}

/**
* @param zipcode the zipcode to set
*/
public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}
}


PersonTest.java

package jaxbtest;

import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import junit.framework.JUnit4TestAdapter;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

/**
*
* @author longtai
*/
public class PersonTest {

public PersonTest() {
}

public static junit.framework.Test suite() {
return new JUnit4TestAdapter(PersonTest.class);
}

@BeforeClass
public static void setUpClass() throws Exception {
}

@AfterClass
public static void tearDownClass() throws Exception {
}

@Test
public void testMarshal() throws Exception {
Person p = new Person();
p.setName("longtai");
p.setEmail("longtai.tw@gmail.com");
Address a = new Address();
a.setAddress("台灣新竹");
a.setZipcode("35002");
p.setAddress(a);

StringWriter writer = new StringWriter();
JAXBContext context = JAXBContext.newInstance(Person.class);
Marshaller m = context.createMarshaller();
m.marshal(p, writer);

System.out.println(writer);
}

@Test
public void testUnmarshal() throws Exception
{
StringReader reader = new StringReader("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><person><address><address>%u53F0%u7063%u65B0%u7AF9</address><zip>35002</zip></address><email>longtai.tw@gmail.com</email><name>longtai</name></person>");
JAXBContext context = JAXBContext.newInstance(Person.class);
Unmarshaller um = context.createUnmarshaller();
Person p = (Person)um.unmarshal(reader);

System.out.println(p.getName());
System.out.println(p.getAddress().getAddress());
System.out.println(p.getAddress().getZipcode());


}
}

2008-03-25

REST 架構研究 20080325

最近在思考, 系統發展的架構. 希望能夠做到後端服務元件可以跟前端使用者介面分離. 第一次看到 REST 架構的東西, 是在 Google Group 上面看到他的 URL 的樣子. 當時只覺得這樣的寫法, 真是不錯, 不用管道?xxxx=xxx 的方式耶. 當時還不知道, 那就叫做 REST. 這幾天在思考架構, 想到如果可以把前端跟後端的要完全切開, 要怎樣讓前端的 UI 不需要知道後端的implements. SOAP 是一個方法, 但是會不會有太多的資料要處理才可以完成. 後來看到一篇, 講述 Java 是否被淘汰的文章, 裡面提到一個 RIA + REST 會是 Java 對抗 Rails on Ruby 的一個利器. 這個時候才知道 REST 到底是怎樣一個架構.
從 google 找到下面幾篇文章, 可以算是 REST 的入門文章.

理解REST軟件架構

最早提出REST 架構論文

Java REST框架一覽
裡頭提到幾個Java for REST 的framework .

2008-02-27

利用ant 清理 svn 的設定檔

最近, 使用的svn server 硬碟死掛了. 沒有做到備份, 所以必須再做一個新的svn server. 不過還好, 有拿到最後一個版本的work version 在自己的電腦裡面. 但是要如何產生新的檔案重新 commit 上新的 svn server就是 傷腦經的地方.
本來想說要自己用java 寫一個可設定清理檔案的程式. 不過還是上網路去找看看有沒有相關的程式可以用. 先找到有人用 java 寫了一版. 不過下載以後發現 JVM 不和沒有辦法用. 不過還好, 那篇文章有其他人留言, 說可以用ant 來試試看. 所以就手動自己試著下去寫一版 ant clean svn 的設定檔.

想要寫出可以 copy or clean 目錄裡頭 .svn 的功能. 寫了一下發現 ant 本身就有排除svn 的設定檔功能, 所以copy 的部份很簡單, clean 就不在寫了.

ant -f svnclean.xml copy -Dsource=${SourceDir} -Ddest=${DestDir}







2007-12-04

File upload with ajax (form base async)

使用ajax傳送檔案回去server, 找了一下ajax 相關的東西, 發現只能用form 的上把資料傳回去.
這一次的研究希望能夠做到 google mail 那樣的單檔上傳的功能.所以, 預計要達到的目的是, html page 不用重新由server 端產生, 並且可以回傳上傳檔案的相關資料.

client code
















server code

FileUploadParser parser = new FileUploadParser("big5", -1);

Model model = parser.parse(request);
Model fields = (Model)model.get("FormValues");
Model files = (Model)model.get("Files");
Object[] filenames = files.getKeys();

ArrayModel f = new ArrayModel();
for(int i=0;i {
SimpleModel m = new SimpleModel();
m.set("FileName",filenames[i]);

FileItem item = (FileItem)files.get(filenames[i]);
m.set("FileSize",String.valueOf(item.getSize()));

File file = new File(");
try
{
item.write(file);
item.delete();
}
catch (Exception e)
{
e.printStackTrace();
}
f.add(m);
}
model.set("Files",f);
response.setContentType("text/html");
response.getWriter().write(model.toJSON() );

2007-11-06

UFT-8 on Web

最近, 開發網頁被要求採用UTF-8 編碼方式, 不再像以前可以直接使用big5的方式了.
但是, 編碼這種東西就是很傷腦經, ?何全世界不快一點統一電腦裡面的編碼. 不要在這樣搞程式設計師了.
下面是自己試過的幾個作法, 做一個紀錄來保存.
開發環境:
1. Tomcat 5.0
2. Java 1.4 5.0
3. notepad++ , pspad, UltraEdit

1. 用ultraedit 編輯 ansi 格式的html
只有在檔案前面加註, <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
失敗, 這樣的作法 並沒有產生正確的作法
2. 用 notepad++ 編輯 utf8 的 html
只有在檔案前面加註, <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
成功, 這樣會正確的顯示中文.
3. 用 notepad++ 編輯 utf8 的 jsp
失敗, 這樣產生還是亂碼.
4. 用 notepad++ 編輯 utf8 的 jsp
並在檔案前面加註, <%@ page language="java" pageEncoding="UTF-8"%>
成功, 正確顯示中文

上面的案例看起來, html 一定要用 utf-8 方式去編輯檔案, 存檔成utf-8 的檔案, 才有機會做到正確的編碼. 如果要改用jsp編碼, 就一定要在每一個檔案前面加註 pageEncoding.
再去研究jsp 被編輯成 java 以後, 會有讀取文字編碼的問題. 其他文件中說到, 可以藉由修改tomcat JAVA_OPTS -Dfile.encoding=UTF-8 來達到目的. 但是我試驗過了失敗, 這部份要在研究才行.

參考資料:
  1. UTF-8 字符處理在 Web 開發中的應用
  2. JSP/Servlet 中的漢字編碼問題
  3. Tomcat/UTF-8