flink 動態支援依賴jar包提交
我加入2084團隊的這些日子都幹了啥?
學習與實現code經歷
入團隊背景
- 大一下,因為疫情原因在家沒有上學,恰逢2084團隊招新,憑著對技術的熱愛和沒事閒著的心態,通過了覃輝學長的面試加入到團隊,由於我學的是Java,所以自然的幹起了後端。
JavaWeb
- 最開始寫了一個基於socket通訊的小demo,用的是純原生的JavaWeb,這個時期的程式碼很原始,業務邏輯都是自己手工做出的,也很像java程式碼。然後通過學長的指引和自己搜尋的資料,發現:都2020年了,沒有哪一個企業甚至是開發流程使用原生的JavaWeb,更多的是利用可以能夠敏捷開發的Framework,這些framework和工具都是可以幫助開發者快速實現功能的法寶利器,當然他們的底層還是javaWeb等協議封裝出來的。
MySQL
- javaweb之後就是MySQL,資料庫不得不說是一個非常重要的東西,業內開發最普遍的關係型資料庫工具是MySQL和Oracle,而這兩者MySQL佔比80%,學號mysql是進入後端的第一步,當然對於初學者,學一些基礎,能夠操作資料庫,把資料庫的東西拿出來,而對一些更為複雜的知識,如鎖,執行緒排程,索引的效能調優只是初步瞭解,短期學習也用不到。
Tomcat
- 然後初步學習了一些之後,學長髮布了做一個登入註冊的demo。6月份末7月份初,開始著手這個demo。我們都知道,最開始的javaweb服務大都是跑在Tomcat這個web容器中的,對於Tomcat來講,支援java原生的jsp程式碼,對於H5頁面支援不是那麼好,這時的疑慮也很大:為什麼市面上大多數網站好像都是h5?7月12日
MyBatis+Maven
- 當時對於ORM的選擇Hibernate還是MyBatis,全自動Hibernate,半自動MyBatis。MyBatis對於資料庫的物件對映操作支援的很好,而且支援一些高階結果集對映和快取機制,7月15日開始學習mybatis,經過短暫的學習,mybatis初步瞭解,這是打通了mysql和java POJO類的隔閡,更加快速的與java實體類相互聯絡,對於原來的專案做了一個整合,使用Maven構建了pom依賴,就是匯入相關的jar包。
Spring
- MyBatis之後就是Spring,快速的企業開發需要spring支援。第一點是 對於一些物件不需要重複的new ,因為在一個專案中,考慮的不僅僅是速度,還有整體的效能,new 需要棧儲存名索引,堆的變數例項空間,而在一些程式中,我們使用的物件僅僅是一個,但是還是在不同的類中,new顯得沒那麼高的效能;第二點,對於快速的整合一些新東西,比如加日誌排錯,新加了個日誌啟動類,從service層到dao層,在每個類中都需要加入相關程式碼,這堆程式碼的整體協調性不好。Spring引入自動裝配注入DI,控制反轉IOC,面向切面AOP都很好的解決了這些問題。
SpringMVC
- Spring其實沒有對業務的整體邏輯造成什麼改變,只要引入jar包,任何程式都可以是spring的,spring只是改變了生產方式,接下來對於MVC三層架構使用的是SpringMVC,檢視層,模型層,控制層,在用原有的專案整合SpringMVC時也遇到了不少的BUG,尤其是MVC的配置檔案,這時的java程式碼已經有點不像java了,寫配置檔案甚至比業務程式碼還多,配置檔案繁瑣,spring還要尋找上下文context,各種層的配置檔案都得重寫,有時因為一個檔案,甚至一行配置寫不對,整體環境直接掛掉。
伺服器部署,專案上線
- 不過好在在踩了無數個坑之後,修復好了bug,專案可以釋出了,但是這時依然是傳統的Tomcat Web容器方式,我只好把寫過的HTML程式碼和一些java程式碼轉到jsp裡面去,這時的前端h5傳資料給後端是表格,後端給前端是jsp方式。7月19日阿里雲伺服器買到手,幸運的是6月14日後端剛成立時學了Git,然後花了幾天時間簡單學了Linux作業系統,這裡要說Linux比Windows更方便,親身體會。那麼把服務部署到雲端,還是tomcat的web容器。還有一點就是,因為windows本地的環境和雲上的環境不同,導致最開始上傳war包,找不到ip:/8080/login 這個服務,也是配置了好長時間才解決,找了好久才發現mvc的Context配置檔案和本地的不同。
SpringBoot微服務
- 在做好單體的服務之後,感覺SpringMVC這套流程太過於複雜,springBoot封裝了ssm把一切的配置全部寫進application.yaml 一切的jar包全部由maven-pom匯入,而且內嵌Tomact容器,我們只需要專注於業務程式碼就好了。而且微服務還有的好處就是,既可以做單體,又可以做分散式叢集,服務易於擴充套件和拆分,整體服務加一個註冊中心搞定。8月份開始SpringBoot,這時開始進行安卓端+PC端+後端聯調測試了,並開始前後端分離。那麼就需要寫介面文件,這個文件相當於手冊,所有開發人員都用這個手冊,並進行開發。
Swagger介面文件
- 直接把最開始的文件程式碼貼上
swagger: '2.0' info: version: 1.0.0 title: Web Login UI API description: >- A API that shows what Back-end do and grant invoking privileges to all 2084 Team programmers. schemes: - http - https externalDocs: description: | **Complete** documentation describing how to use this API . url: 'http://xiyuan.ren' host: xiyuan.ren basePath: /login tags: - name: user description: Online user's information only has username and password. - name: register description: User's complete information. - name: file description: >- User's want to upload some files ,for example,Feedback Documents. Or other binary files . paths: /users: get: tags: - user summary: Get all online users. description: Returns a list containing all users online .This list supports paging . produces: - application/json consumes: - application/json parameters: - $ref: '#/parameters/pageSize' - $ref: '#/parameters/pageNumber' responses: '200': description: Get all online users. schema: $ref: '#/definitions/Users' examples: application/json: items: - username: 2048團隊666 password: TEAM2048fly - username: '抗擊病毒,從你我做起' password: DeafeatVirus666 - ... and more ... '400': description: No user online. '500': $ref: '#/responses/Standard500ErrorResponse' default: $ref: '#/responses/DefaultErrorResponse' /user: post: tags: - user summary: Login description: Add a new user to the online user list . produces: - application/json consumes: - application/json parameters: - name: user in: body schema: $ref: '#/definitions/User' responses: '200': description: 'The user logins successfully,means binding its device.' '400': description: >- The user online failed,probably username doesn't exist or password is incorrect. '500': $ref: '#/responses/Standard500ErrorResponse' default: $ref: '#/responses/DefaultErrorResponse' '/user/{username}': get: tags: - user summary: Get a user by username. description: Returns a user via parameter username . produces: - application/json consumes: - application/json parameters: - $ref: '#/parameters/username' responses: '200': description: The user is founded. schema: $ref: '#/definitions/User' '400': $ref: '#/responses/UserDoesNotExistResponse' '500': $ref: '#/responses/Standard500ErrorResponse' default: $ref: '#/responses/DefaultErrorResponse' '/user/{username}{password}': delete: tags: - user summary: Logout description: 'Remove the user from online list,means unbinding its device.' produces: - application/json consumes: - application/json parameters: - $ref: '#/parameters/username' - $ref: '#/parameters/password' responses: '200': description: 'User Logout,unbinding.' '400': $ref: '#/responses/UserDoesNotExistResponse' '500': $ref: '#/responses/Standard500ErrorResponse' default: $ref: '#/responses/DefaultErrorResponse' /register: post: tags: - register summary: A new user to register. description: Add a new user to our service database. parameters: - name: register in: body schema: $ref: '#/definitions/Register' produces: - application/json consumes: - application/json responses: '200': description: Register successfully . '400': description: >- Probobly user's error ,for example the password and ensure password is not equals,please show a web popup to user instead of 400error we will not permit the information convey to the back-end. '500': $ref: '#/responses/Standard500ErrorResponse' default: $ref: '#/responses/DefaultErrorResponse' security: - userAPIKEY: [] /registers: get: tags: - register summary: Get all registers. description: Get all registered users. produces: - application/json consumes: - application/json responses: '200': description: Gets successfully . schema: $ref: '#/definitions/Registers' examples: application/json: items: - username: 2048團隊666 password: TEAM2048fly ensurepassword: TEAM2048fly email: [email protected] sex: male registerTime: '' '': '' - ....: null '400': $ref: '#/responses/UserDoesNotExistResponse' '500': $ref: '#/responses/Standard500ErrorResponse' default: $ref: '#/responses/DefaultErrorResponse' security: - userAPIKEY: [] '/register/{username}{password}': put: tags: - register summary: An user to update . description: update user's information from the database . parameters: - $ref: '#/parameters/username' - $ref: '#/parameters/password' produces: - application/json consumes: - application/json responses: '200': description: update user's information successfully .Database forever exists. '400': $ref: '#/responses/UserDoesNotExistResponse' '500': $ref: '#/responses/Standard500ErrorResponse' default: $ref: '#/responses/DefaultErrorResponse' security: - userAPIKEY: [] delete: tags: - register summary: An user to destroy . description: >- Delete the user from the database,the user information will never occur in our server. produces: - application/json consumes: - application/json parameters: - $ref: '#/parameters/username' - $ref: '#/parameters/password' responses: '200': description: >- delete the user successfully and the user will never exist in our database forever . '400': description: User does not exist in our server. '500': $ref: '#/responses/Standard500ErrorResponse' default: $ref: '#/responses/DefaultErrorResponse' security: - userAPIKEY: [] '/text/{username}': post: tags: - file summary: the text user's uploaded description: >- The feedback that the user write in a small box.We want the feedback restricted to 300 words per time. parameters: - $ref: '#/parameters/username' - name: Feedback text in: body description: User's feedback schema: type: string format: formData produces: - application/json consumes: - application/json responses: '200': description: Feedback is received successfuly. '400': description: Feedback is missing. '500': $ref: '#/responses/Standard500ErrorResponse' default: $ref: '#/responses/DefaultErrorResponse' security: - userAPIKEY: [] '/image/{username}{password}{image}': post: tags: - file summary: the image icon user's uploaded description: the feedback that the user write in a small box. consumes: - application/json parameters: - $ref: '#/parameters/username' - $ref: '#/parameters/password' - name: image in: path required: true type: string format: file produces: - image/png - image/gif - image/jpeg - application/json - application/x-yaml responses: '200': description: image is received successfuly. '400': description: image is missing. '500': $ref: '#/responses/Standard500ErrorResponse' default: $ref: '#/responses/DefaultErrorResponse' '/image/{username}': get: tags: - file summary: Gets an user's image. consumes: - application/json parameters: - $ref: '#/parameters/username' produces: - image/png - image/gif - image/jpeg - application/json - application/x-yaml responses: '200': description: The user's image find successfully. '404': $ref: '#/responses/UserDoesNotExistResponse' '500': $ref: '#/responses/Standard500ErrorResponse' default: $ref: '#/responses/DefaultErrorResponse' securityDefinitions: userbasic: type: basic userAPIKEY: name: userAPIKEY in: header type: apiKey userOauth2: type: oauth2 flow: accessCode authorizationUrl: 'http://' tokenUrl: 'http://' definitions: Register: required: - username - password - ensurePassword - phone properties: username: $ref: '#/parameters/username' password: $ref: '#/parameters/password' ensurePassword: type: string description: >- The ensure password must absolutely equals to the password, I wanna that if the ensurePassword not equals password ,an alertion will be occured in the web page{兩次密碼不一致!},while not to convey the error to the back-end. email: type: string description: To send emails. sex: type: string description: 'three options is best choice male ,female or the keep secret' registerTime: type: string format: dateTime readOnly: true example: '2001-08-17T16:07:06Z' avatorBase64PNG: type: string format: byte phone: type: string description: To send Verification code. Registers: properties: items: type: array minItems: 0 maxItems: 100 uniqueItems: true items: $ref: '#/definitions/Register' User: required: - username - password properties: username: $ref: '#/parameters/username' password: $ref: '#/parameters/password' Users: properties: items: type: array minItems: 0 maxItems: 100 uniqueItems: true items: $ref: '#/definitions/User' Error: properties: code: type: string default: 500 message: type: string default: ERROR description: The Error message can be DIY . OK: properties: message: type: string default: OK description: The OK message can also be DIY . parameters: username: name: username in: path required: true description: >- The user's username .The username is the identification of every users.So it is a unique field.The string length must range 1-64,the Chinese character is also allowed,tell the user how to fill,when the username is not availiable please show the message in webPages {使用者名稱重複!}. type: string password: name: password in: path required: true pattern: '[a-zA-Z0-9]{8-64}' description: >- Please give the user description on how to fill the password.The string length must range 8-64,if less 8 tells user {可能不安全!}.And every letter must be a-z A-Z 0-9,other word is not avaliable.The user’s password is the key for the user to login and bind to the computer. After transform from webPage to the Server backend.The password will be encrypted by MD5, the letters are all unified into uppercase. type: string format: password pageSize: name: pageSize in: query description: Number of users returned type: integer minimum: 0 exclusiveMinimum: true maximum: 100 exclusiveMaximum: true default: 20 pageNumber: name: pageNumber in: query description: pageNumber type: integer minimum: 0 exclusiveMinimum: true maximum: 100 exclusiveMaximum: true default: 20 responses: AlltheRequestCorrectResponse: description: >- No Errors and no warnings,all the things seem to be perfect.Always code {2**} to user. schema: $ref: '#/definitions/OK' examples: application/json: message: OK UserDoesNotExistResponse: description: >- User does not exist,I want the web page can give the message{user=null} to the back-end.Always status code{4**} to user. schema: $ref: '#/definitions/Error' examples: application/json: code: '404' message: NotFound Standard500ErrorResponse: description: >- An unexpected error occured .This can be a nonsense error or a server error,please definate by yours.Always status code{5**} to user. schema: $ref: '#/definitions/Error' examples: application/json: code: '500' message: ServerError DefaultErrorResponse: description: >- Unknown error,The server knows none,the Web Pages knows none.Alway status code{963} or none. schema: $ref: '#/definitions/Error' examples: application/json: code: '963' message: UnknownError
這個介面文件寫完就不能修改了,所以要和其他端的人員商量好,這個開始我們沒有商量好,造成了一點麻煩。還有一點就是,我以為前後端開發是web前端和web後端,所以我這邊寫完上線就找那邊測試,但是搞烏龍了,安卓端是前端,web前端還是我們寫,於是在8月23日聯合測試介面之後,我用Bootstrap又寫了一下web前端,8月末優化了前端頁面與使用者體驗。
在最開始的時期文件需要寫,但Springboot階段文件用註解直接生成的,一些註解搞定了文件排布,文件和這些介面只對於開發者可見。
Web前端
- web前端基於Bootstrap響應式佈局和Semantic-UI圖示 訪問 http://121.41.229.179:8081 可以看到,並且可以註冊
比如登陸註冊服務的web端是javascript+jqueryAjax 進行快速響應來 優化使用者體驗。
比如:
SpringSecurity
- 這個網站集成了 使用者管理介面,前端頁面,swagger-ui開發者文件,安卓端及PC端相關介面,聯調過了可以使用,並且我還在內部設定了許可權管理,不同的人(開發者admin,普通使用者 normal,管理員master,付費使用者vip)能看到的內容和服務是不同的,這也方便了以後網站開發的維護。這些功能的實現基於SpringSecurity的建立,目前的註冊業務只有郵箱,因為個人原因(身份證到期,辦理較慢)沒有簡訊業務和域名配置,這些功能會在後續完善。
現在利用的security還是沒有找到OAuth2第三方鑑權和認證的解決方法,這個後續會整合進服務中。
學長讓我把可能的密碼md5加密,我想還是不用了,因為本身security就有一個加密的機制,在加一個會不會顯得畫蛇添足?這個後續可以商量....
Docker部署
- 由於容器技術的發展Docker部署成了開發者必備的技能,極大簡約開發部署上線環節,DevOps營運而生,Docker部署需要一定的知識,我也學了差不多半個月,好處是映象是疊加的,減少伺服器開銷,方便查閱日誌,容器互聯,資料掛載在磁碟分割槽,容器刪除資料不會丟失.........
現在後端的部署模式是整體服務用maven構建專案,springboot部署整個微服務(基本上是註解),配置檔案就一個application.yaml 然後Docker部署應用(構建build+Dockerfile+容器服務打通埠上線)
-----至此就是我加入2084團隊期間做的事情
未來與展望
短期目標
把目前的Oauth2,TOKEN做好,實現第三方登入,與MQTT南東平那邊互聯一下.
長期目標
身為2084團隊一員,肯定希望把服務做好,我對於服務地整體部署環節瞭解的還算可以,那麼接下來呢,我認為
微服務架構圖
但目前我覺得分散式註冊中心不可行,因為單體的目前沒做好,使用者也...,一上來就分散式也浪費
隨著時間的增長,個人技術棧是疊加的,考慮的問題也更復雜,但是,學長,我認為先做單體,然後再分散式,至於內網穿透NAT給點時間。