前言:

這些學習主要都是針對Mooc 上面的課程(Programming Cloud Service)所學到的一些部分.

 心得:
第二個作業不確定是不是最後的作業,但是卻相當的有趣.主要是透過架設OAuth2 的Server 然後去搭配測試程式的Client來做Video是否有喜歡 (like)的操作.
裡面幾個邏輯都算是很簡單,比如說Video不能被同一個使用者喜歡兩次. 喜歡的Video是必須存在的….

主要的難度,還是在跟Https 與 OAuth2的部分,不過由於我有習慣從第一個範例開始就寫同一個程式然後慢慢去改~慢慢學習裡面的幾個比較奧妙的地方.
所以這次的作業反而相當快就寫完了.

很值得修的課程,對於 HTTPS, OAUTH都有相當清楚地介紹,想要了解透過Exclipse去架設Java Server (不論是 Jetty 或是 Tomcat)這都是好選擇.
當然如果你對於Eclipse上面Gradle不太熟,這個也可以告訴你怎麼學習啊~~因為我也卡了很久.主要就是每次加了新component 之後都忘記要 Gradle->Refresh.

最後提一下學這堂課的動機吧,第一個部分是希望好好把Cloud Programming 有系統地學一下,雖然說懂 JSON,REST跟 OAuth.但是詳細的原理跟真正在Java (畢竟JSON是Java出來的)上要如何實現才能真正的了解;另外一個原因就是因為我一直以來對於Java與使用Eclipse有一種排斥感(雖然我修過Scala),但是我希望透過這個學習會讓我更熟悉這些部分.

我學習的Github 在這裏

  

課堂筆記:

  • @ComponentScan 會搜尋指定範圍的原件,是會重啟Spring.除了一些PaaS可能會踢掉之外(GAE?),一般而言並不會造成任何效能上的影響.

  • @Autowired 對應著Application.java 的一個@Bean/@Component/@Service/@Repository,可以讓他根據不同狀況來改變injection 不同的class. 如果沒有@Bean在Application 會產生exception.

    • 使用上可以類似C++的繼承方式,使用 @Autowired 在一個parent class上.然後利用@Bean 或其他的方式來mapping 到你需要的child class來改變或是更換你需要的物件.
  • Java Persistence API @Entity @Respository 需要做以下的事情
    • 需要在Grandle 先加上以下的資訊

      • compile(“org.springframework.boot:spring-boot-starter-data-jpa:${springBootVersion}”)       

      • compile(“jdbc:jdbc:2.0”)    

      • compile(“com.h2database:h2”)    

    • 如果要連接一些資料庫,也需要在application.properties裡面設定好

      • spring.datasource.url=jdbc:mysql://localhost/test

      • spring.datasource.username=dbuser

      • spring.datasource.password=dbpass

      • spring.datasource.driverClassName=com.mysql.jdbc.Driver

  • About Data REST

    • 要把整個Spring 從controller 改成由這個改變)

      • Application 繼承RepositoryRestMvcConfiguration

      • Gradle 要加入compile(“org.springframework.data:spring-data-rest-webmvc”)

      • 整個Controller 不再需要,直接移除後開始使用 VideoRepository

      • 修改 VideoRepository 傳回與接收直,注意以下事項: (參考另外一個改變)

        • findByXXX 必須回傳 Collection 不然就會錯誤<

        • addVideo 不回傳

    • 重要的是必須要 ObjectMapper弄好~不然傳回HATEOS就沒辦法直接使用/li>

  • Spring Security 增加一些安全性的保護(登入機制)並且利用加密的cookie來辨別身份,並且可以根據使用者權限來決定可以執行的REST指令或是要求.

    • 要加上https的支援,必須要做以下的修改:

      • 加入mainresourcesprivatekeystone (如何產生看這裡)

      • 要把Jetty 改成用tomcat

        • compile(“org.springframework.boot:spring-boot-starter-web:${springBootVersion}”)    

        • compile(“org.springframework.boot:spring-boot-starter-tomcat:${springBootVersion}”)

      • 必須在Application 加入以下的東西

        • @Bean

        • EmbeddedServletContainerCustomizer containerCustomizer()

      • 千萬記住在test那邊要把網址改成 https://localhost:8443/ 而且在properties 裡面設定的 SERVER_PORT=9000 也沒有效果

    • 要加上login redirection 需要完成以下的修改: (參考以下修改  )

      • Add in build.gradle    

        • compile(“org.springframework.boot:spring-boot-starter-security:${springBootVersion}”)
      • 需要新增一個class 繼承  WebSecurityConfigurerAdapter 來處理帳號與login/logout的問題與設定.

        • 必須要加上以下兩個設定,不然啟動的時候會有問題

          • @Configuration// Setup Spring Security to intercept incoming requests to the Controllers

          • @EnableWebSecurity

      • 在unit test的時候,需要注意以下的部分:

        • 根據目前的設定,任何的method都需要登入才能執行. 不然會跳出exception 可以由retrofit 接過來為 HttpStatus.SC_MOVED_TEMPORARILY

        • logout後應該也是要發生,exception 如果要試著去執行任何指令.

    • 課程以外,我把關於認證的部分做了一點小研究,主要就是根據不同的使用者權限來設定哪些方法可以執行~哪些會失敗 (參考Github)

         @Autowired public void    
         configureGlobal(AuthenticationManagerBuilder auth)
    { 
    auth .inMemoryAuthentication() .withUser("user") 
    //#1 
    .password("password") .roles("USER") 
    .and() .withUser("admin") // #2 
    .password("password") .roles("ADMIN","USER"); 
    } 
  • 前面設定密碼是一樣的,就不重複敘述,這裡唯一要注意的,由於HasRoles 是使用字串,所以大小寫是有差別的.

  • 最後來到OAuth2,要完成OAuth2 需要有以下的步驟:

    • 先要在build.gradle 裡面加上:

      • compile(“org.springframework.security.oauth:spring-security-oauth2:2.0.0.RC2”)    

      • compile(“org.springframework.security.oauth:spring-security-oauth2-javaconfig:1.0.0.M1”)

      • compile(“org.apache.httpcomponents:httpclient:4.3.4”)

    • 新增檔案去控制 UserDetails 與 UserDetailsService (參考: 這個改變)

    • 針對Retrofit 的client 部分,需要implement 更多關於OAuth的部分,主要是:

      • 新增一個OAuthHandler 去負責 RequestInterceptor

      • 並且直接修改 RestAdapter.Builder 去新增OAuth的處理.

  • 在開發這種有client跟server的程式的時候,特別要注意的是如果發現有問題的時候,需要去釐清究竟是server還是client的問題.

    • 如果是學習這個課堂的範例的話,可以考慮跑跑課堂內附的client搭上你自己寫的server.有時候問題是出在client而不是你server有問題.

    • 如果是web server (Tomcat 或是 jetty )可能比較麻煩~需要一步步把所加上的部分蓋掉來追蹤.

    • 千萬要注意 @PathVariable 跟  @RequestParam的差異,簡單解釋一下:

      • @PathVariable 是當你使用 GET Path 為參數比如說  video/2 

      • @RequestParam 雖然也走GET但是卻不是Path 而是會以其他方式傳遞.

  • 有個需要注意的部分是,關於回傳Http.Status Exception Code

    • 404:  Resource Not Found 

      • 可以直接用 throw new ResourceNotFoundException();
    • 400: Bad Request

      • 可以繼承 RuntimeExcption然後依照以下修改

        • @ResponseStatus(value = org.springframework.http.HttpStatus.BAD_REQUEST)

        • public final class BadRequestException extends RuntimeException  {   //  class definition}

參考:

 


Buy Me A Coffee

Evan

Attitude is everything