2019年9月23日 星期一

TortoiseGit set default pull remote

這功能在TortoiseGit叫做"Tracked branch"

資料夾右鍵 -> 點Browse References (如下圖)

對branch右鍵 -> 點Select tracked branch (如下圖)
註:Tracked branch這欄就是default remote branch

選擇remote branch就設定完畢

2018年8月26日 星期日

Spring Filter - RESTFUL Log

最直接的方式就在每個method內直接加入restful log

但這樣就太囉嗦

所以改用filter來處理這件事情

但由於request body只能被讀取一次的特性

所以filter要針對request動點手腳

@WebFilter(
    filterName="testFilter",
    urlPatterns={"/testRest"}
)
public class SpringRequestBodyFilter extends OncePerRequestFilter{
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        BodyReaderHttpServletRequestWrapper requestWrapper = new BodyReaderHttpServletRequestWrapper(request);
        System.out.println("body: " + requestWrapper.getBody());

        filterChain.doFilter(requestWrapper, response);
    }
}

public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper{
    private final String body;

    public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        try(BufferedReader bufferedReader = request.getReader()){
            body = request.getReader().lines().collect(Collectors.joining());
        }
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        return new DelegatingServletInputStream(new ByteArrayInputStream(body.getBytes()));
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }

    public String getBody() {
        return this.body;
    }
}
第10行將HttpServletRequest包裝成BodyReaderHttpServletRequestWrapper傳給filter

BodyReaderHttpServletRequestWrapper的功能就是先讀取request body並存到body欄位中
由於前面提到過request body只能讀取一次的特性
所以要重新建立inputStream和reader
若有用到inputStream或reader時才不會出現Stream closed的錯誤

第29行這邊我用org.springframework.mock.web.DelegatingServletInputStream
這個是用spring test的(要自己實作ServletInputStream也可以,但已有寫好的沒有不拿來用的理由)

完整程式可參考https://github.com/softmenlouis/springBoot-filter.git

Spring Filter

1.使用Java自己本身的Filter
@SpringBootApplication
@ServletComponentScan("test.annotation.filter")
public class SptringAnnotationFilterApplication {
    public static void main(String[] args) {
        SpringApplication.run(SptringAnnotationFilterApplication.class, args);
    }
}


@WebFilter(
    filterName="testFilter",
    urlPatterns={"/testRest"}
)
public class SpringAnnotationFilter implements Filter{
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws IOException, ServletException {
        // do something

        filterChain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}
SptringAnnotationFilterApplication
1. 設定@ServletComponentScan(filter的package)

SpringAnnotationFilter
1. implements javax.servlet.Filter
2. 設定@WebFilter(urlPatterns是設定哪些url要filter)
3. 改寫doFilter

這樣filter就可以生效

註:
若有多個filter時,在這邊使用Spring的@Order是沒有用的
真的要使用order的話可以參考下面第二種作法or使用package name去控制filter順序

2.使用Spring的FilterRegistrationBean
@SpringBootApplication
public class SpringBeanConfigFilterApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBeanConfigFilterApplication.class, args);
    }
}

@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean<Filter> registFilter() {
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new SpringBeanConfigFilter());
        registration.addUrlPatterns("/testRest");
        registration.setOrder(2);
        registration.setName("testFilter");
        return registration;
    }

    @Bean
    public FilterRegistrationBean<Filter> registFilter2() {
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new SpringBeanConfigFilter2());
        registration.addUrlPatterns("/testRest");
        registration.setOrder(1);
        registration.setName("testFilter2");
        return registration;
    }
}

public class SpringBeanConfigFilter implements Filter{
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws IOException, ServletException {
        // do something

        filterChain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}

public class SpringBeanConfigFilter2 implements Filter{
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws IOException, ServletException {
        // do something

        filterChain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}

使用Spring bean的方式去做設定
註:此設定的方式可以設定filter order

完整程式可參考https://github.com/softmenlouis/springBoot-filter.git

2018年8月8日 星期三

Multiple MongoDB connectors

pom.xml配置
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.0.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
    <version>2.0.4.RELEASE</version>
</dependency>

Application設定
@SpringBootApplication(
    exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class}
)
public class TestApplication {
    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }
}
最重要的就是要設定 exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class}

application.properties設定
mongodb.connect1.uri=mongodb://自己的連線設定1
mongodb.connect1.database=自己的database1

mongodb.connect2.uri=mongodb://自己的連線設定2
mongodb.connect2.database=自己的database2

Configurer設定
@Configuration
public class TestConfigurer{
    @Bean
    @ConfigurationProperties(prefix = "mongodb.connect1")
    public MongoProperties getConnectionSetting1() {
        return new MongoProperties();
    }

    @Bean
    @ConfigurationProperties(prefix = "mongodb.connect2")
    public MongoProperties getConnectionSetting2() {
        return new MongoProperties();
    }

    @Bean(name="Template1")
    public MongoTemplate mongoTemplate1(){
        MongoProperties p = getConnectionSetting1();
        
        return genMongoTemplateWithMongoProperties(p);
    }

    @Bean(name="Template2")
    public MongoTemplate mongoTemplate2(){
        MongoProperties p = getConnectionSetting2();

        return genMongoTemplateWithMongoProperties(p);
    }

    private MongoTemplate genMongoTemplateWithMongoProperties(MongoProperties p){
        MongoClientURI uri = new MongoClientURI(p.getUri());
        MongoClient client = new MongoClient(uri);

        SimpleMongoDbFactory f = new SimpleMongoDbFactory(client, p.getDatabase());
        return new MongoTemplate(f);
    }
}

Dao使用Template
@Repository
public class TestDao {
    @Autowired
    @Qualifier("Template1")
    private MongoTemplate mongoTemplate1;

    @Autowired
    @Qualifier("Template2")
    private MongoTemplate mongoTemplate2;
}

eclipse plus properties edit

eclipse properties編輯小工具 http://propedit.sourceforge.jp/index_en.html

2017年6月26日 星期一

Java 歷史特性 (5 ~ 7)

JAVA 5


  • 泛型
  • 自動封裝與解封裝
  •   例:
    long i = new Long(1);
    
  • 列舉(Enumerations)
  • 可變參數函式(Varargs)
  •   例:
    public void mehtod(String... args)
    
  • for each
  • Annotation
  • 改進多執行緒JAVA 程式的執行語義
  • 匯入靜態類別
  •   例:
    static import java.lang.System.*;
    
    public class HelloWorld {
        public static void main(String args[]){
            out.println("Hello World.");
        }
    }
    

    JAVA 6

    建議直接參考原文:IBM - Java SE 6 新特性系列

  • Instrumentation 新功能
  •     動態載入/替換class
  • HTTP 增强
  • JMX 與系统管理
  • 編譯器 API
  • Java DB 和 JDBC 4.0
  •     Java DB (Derby) (Java內建DB)
        JDBC一些強化
  • 對腳本語言的支持
  • XML API 與 Web 服務
  • JAVA 7


  • 泛型寫法簡化
  •   例:
    HashMap<String, String> map = new HashMap<>()
  • Multi-catch
  •   例:
    try{
    
    }catch(NullPointerException | IllegalArgumentException e){
        e.printStackTrace();
    }
    
  • try-with-resources
  •   例:
    try(FileReader reader = new FileReader("file")){
    
    }catch(IOException){
    	e.printStackTrace();
    }
    
      在try中的資源,有實作java.lang.AutoCloseable的話
      於程式結束時會自動去call close方法

  • switch 支援字串
  • 數字可用下劃線「_」分隔
  •   例:123_456
  • byte,short,int,long 可用二進制表達
  •   例:int a = 0b01111;(數字前加0b)


    參考連結:
    wiki - Java_5.0
    IBM - Java SE 6 新特性系列

    2017年5月10日 星期三

    紅豆粽子

    材料:
    紅豆 1 斤 (600公克)
    6 兩 (250公克)
    1 斤 (600公克)
    糯米 2 斤 (1200公克)(1 斤約有10個粽子)

    糯米泡半天水

    準備餡料:
    1. 將紅豆煮爛(約1.5小時)
    2. 將紅豆加水放在漏盆中壓爛,下面用臉盆接
     目的有2點:a.去殼 b.取紅豆泥
    示意圖:

    3. 將第2步驟的紅豆泥水放到豆漿過濾袋脫水
    4. 將紅豆、糖、豬油一起下鍋去攪拌
     油的話推薦使用豬油 (比較香) (另外豬油最好的是板油)
     吃素的話可以用植物油
    (植物油的話要炒久一點,讓水分少一點比較好弄成一團一團的餡料)
     完成後約可以得到2斤的紅豆泥
    5. 在以1球約55公克的紅豆泥捏成長條狀

    6. 放冷凍
    到這邊為止餡料告一段落

    綁粽子:
    1. 取兩片粽葉
     粽葉有兩面,一面為光滑面,一面為粗糙面(梗突起的為粗糙面)
     光滑面朝上
    2. 將粽葉頭對尾重疊
    圖一 圖二
    3. 凹出容器的形狀(不要從中間凹,從1/4 or 3/4 處凹)
     看手順:
      凹右半邊要用第2點的圖一
      凹左半邊要用第2點的圖二

    4. 塞米塞紅豆餡
    5. 將粽葉閉合(待施工...)
    6. 用繩子綁起來

    大鍋水煮粽子約2小時

    完成!!!