知識(shí)
不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價(jià)值,我們?cè)谧非笃湟曈X表現(xiàn)的同時(shí),更側(cè)重于功能的便捷,營(yíng)銷的便利,運(yùn)營(yíng)的高效,讓網(wǎng)站成為營(yíng)銷工具,讓軟件能切實(shí)提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序?yàn)楹笃谏?jí)提供便捷的支持!
您當(dāng)前位置>首頁 » 新聞資訊 » 網(wǎng)站建設(shè) >
在Android上做服務(wù)端開發(fā)/Web開發(fā)/SpringMVC開發(fā)
發(fā)表時(shí)間:2018-9-26
發(fā)布人:葵宇科技
瀏覽次數(shù):69
一部分Android開發(fā)者看到這個(gè)標(biāo)題時(shí)可能有點(diǎn)疑惑,SpringMVC不是用來做JavaWeb開發(fā)的嗎?難道被移植到Android上來了?答案是否定的,因?yàn)镾pringMVC是基于Servlet的,在Android上開發(fā)一個(gè)支持Servlet的容器(Tomcat、JBoss)可不簡(jiǎn)單,所以我們是在Android上開發(fā)了一套全新的WebServer + WebFramework。
AndServer2.0基于編譯時(shí)注解實(shí)現(xiàn)了SpringMVC的大部分注解Api,其Request的分發(fā)流程也基本和SpringMVC一致,與SpringMVC最大的不同是SpringMVC基于運(yùn)行時(shí)注解,并且SpringMVC提供的功能更多更強(qiáng)大。不過AndServer提供的功能在Android上來做服務(wù)端開發(fā)是完全足夠的。
看到這里讀者朋友應(yīng)該知道了,AndServer2.0是使用注解開發(fā)Web程序的,為了有個(gè)更直觀的了解,我們先看一個(gè)模擬用戶登錄的Http Api:
@RestController
public class UserController {
@PostMapping("/login")
public String login(@RequestParam("account") String account,
@RequestParam("password") String password) {
if(...) {
return "Successful";
}
return "Failed";
}
}
假設(shè)服務(wù)端的Address是192.168.1.11
,監(jiān)聽的端口是8080
,那么通過http://192.168.1.11:8080/login
就可以訪問該登錄Http Api了。
感興趣的讀者可以幫我們做一下Code Review:
https://github.com/yanzhenjie/AndServer
下文將依次介紹以下三點(diǎn):
- 系統(tǒng)層架構(gòu)
- 應(yīng)用層架構(gòu)
- 使用示例
1. 系統(tǒng)層架構(gòu)
我們都知道Http是根據(jù)Http協(xié)議使用Socket做了連接屬性、數(shù)據(jù)格式、交互邏輯方面的包裝,我們來模擬一段服務(wù)端啟動(dòng)Server的代碼:
public void startServer(String address, int port) {
InetAddress inetAddress = InetAddress.getByName();
ServerSocket serverSocket = new ServerSocket(8080, 512, inetAddress);
while (true) {
Socket socket = serverSocket.accept();
HttpConnection connection = HttpParser.parse(socket);
HttpThead thread = new HttpThread(connection);
thread.start();
}
}
ServerSocket
監(jiān)聽了某個(gè)端口,當(dāng)有Socket
連接上來的時(shí)候去把這個(gè)Socket
解析為HttpConnection
,解析過程是按照Http協(xié)議擬定的格式,從Socket
的InputStream
讀取一些數(shù)據(jù)后,用Request
和Response
包裝Socket
和未讀取的流(比如標(biāo)記下次讀取流的起點(diǎn)),下文會(huì)再提到。
接著HttpParser
用HttpConnection
包裝了Request
和Reponse
返回,可想而知,作為服務(wù)端程序,HttpConnection
至少包涵了Request
和Response
對(duì)象:
public class HttpConnection {
private Request mRequest;
private Response mResponse;
...
}
緊接著啟動(dòng)了一個(gè)線程去處理當(dāng)前連接,其實(shí)也就是處理當(dāng)前Request
,用Response
寫出數(shù)據(jù),怎么處理這個(gè)Request
是一個(gè)WebFramework的核心,作為Http服務(wù)端程序,應(yīng)該能提供Html文件、JS文件、Java Method(Http Api)等讓客戶端訪問,因此得有一個(gè)管理員來負(fù)責(zé)請(qǐng)求和資源的匹配,所以有一個(gè)叫做HttpDispatcher
的類來決定這個(gè)Request
應(yīng)該發(fā)給哪個(gè)資源去處理:
public class HttpDispatcher {
public void dispath(Request request, Response response) {
...
}
}
在HttpThead
里面,當(dāng)線程被喚起時(shí)只需要負(fù)責(zé)調(diào)用HttpDispatcher#diaptch()
即可,到這里就比較清晰了,只需要HttpDispatcher
把當(dāng)前Request
派發(fā)到對(duì)應(yīng)的Html File或者Java Method處理就可以了,具體的處理就屬于HttpFramework的事,我們下文再講。
這就是一個(gè)簡(jiǎn)單的WebServer的藍(lán)圖,我們根據(jù)設(shè)想畫出了系統(tǒng)層架構(gòu)圖:
系統(tǒng)層運(yùn)行時(shí)流程圖:
上圖中,Handler
表示處理請(qǐng)求的操作手柄,可能是Html File或者Java Method。值得高興的一點(diǎn)是,在我們迭代了幾個(gè)版本后,發(fā)現(xiàn)Apache組織提供了上述藍(lán)圖中的HttpParser
層,因此為了穩(wěn)定性和節(jié)省人力我們已經(jīng)替換該層為Apache的實(shí)現(xiàn)。
2. 應(yīng)用層架構(gòu)
應(yīng)用層就是上文中提到的WebFramework,也就是上一個(gè)小節(jié)流程圖的Framework
層,包括了Session的處理、Cookie的處理、Cache的處理等。
接著上文,HttpDispatcher
需要把當(dāng)前Request
派發(fā)到對(duì)應(yīng)的Html File或者Java Method處理,而Handler
代表了Html File或者Java Method,因?yàn)榇硕邊^(qū)別極大,用一個(gè)類來表示它們顯然有些不合理,于是我們想到了使用Adapter
模式,所以有了一個(gè)抽象類RequestHandler
:
public abstract class RequestHandler {
public abstract void handle(Request request, Response response);
}
RequestHandler
可以表示任何文件或者Java Method,HttpDispatcher
的作用是分發(fā)請(qǐng)求到各個(gè)資源,所以HttpDispatcher
不應(yīng)該來分析某個(gè)RequestHandler
具體是什么東西,它應(yīng)該直接調(diào)用RequestHandler
來處理請(qǐng)求,因?yàn)镠tml File或者Java Method對(duì)應(yīng)的RequestHandler
在實(shí)現(xiàn)上顯然大有不同,所以這里適用Adapter
模式,于是我們用HandlerAdapter
去做RequestHandler
的適配:
public class HandlerAdapter {
public RequestHandler getHandler(Request request) {
...
}
...
}
HandlerAdapter
除了能獲取RequestHandler
之外,還需要做一些描述性的工作,好讓HttpDispatcher
知道當(dāng)前適配的RequestHandler
是可以處理正要分發(fā)的這個(gè)Request
的。
因?yàn)镠tml File和Java Method的返回值又是大相徑庭,因?yàn)榉祷刂凳禽敵龅娇蛻舳苏故镜?#xff0c;所以我們把返回值抽象為View
:
public class View {
public Object output() {
...
}
...
}
如上所以,output()
方法就是獲取Handler
輸出的內(nèi)容,還有其他方法是對(duì)這個(gè)輸出的描述,這里不例舉。
因?yàn)?code>View是返回值,沒有具體的交互了,所以不適用Adapter
模式了,因此我們必須有一個(gè)處理返回值的機(jī)制,把處理返回值的機(jī)制叫做ViewResolver
:
public class ViewResolver {
public void resolver(View view, Request request, Response response) {
...
}
}
在ViewResolver
中根據(jù)輸出內(nèi)容的類型不同,處理方式也不同,最終把輸出內(nèi)容通過Response
對(duì)象寫出去,底層是使用上文中提到的被Response
包裝的Socket
寫出。
這就是一個(gè)簡(jiǎn)單的WebFramework的藍(lán)圖,我們根據(jù)設(shè)想畫出了應(yīng)用層架構(gòu)圖:
應(yīng)用層運(yùn)行時(shí)流程圖:
上圖中,Interceptor
表示對(duì)請(qǐng)求的攔截器,比如可以做一些不允許沒登錄或者沒權(quán)限的請(qǐng)求進(jìn)入的工作。ExceptionResolver
表示全局異常處理器,比如某個(gè)Api發(fā)生了異常,會(huì)轉(zhuǎn)到ExceptionResolver
中處理,而不至于當(dāng)前請(qǐng)求不響應(yīng)或者響應(yīng)了不想被客戶端看到的消息。
另外需要補(bǔ)充的是,上文中提到的都是粗略的設(shè)計(jì),中間還有一些細(xì)節(jié),例如Session的處理、Cookie的處理、緩存的處理等都未提到,其中任何一個(gè)知識(shí)點(diǎn)單獨(dú)拿出來都可以寫一篇文章,由于篇幅關(guān)系這里不做詳細(xì)介紹。
架構(gòu)設(shè)計(jì)和流程到此就都介紹完了,有興趣的開發(fā)者也可以自己實(shí)現(xiàn)一下。
3. 使用示例
AndServer對(duì)于方便使用的理念是:只需要添加注解即可,不需要再做額外的配置。所以除了像文章開頭那樣用注解寫好Api之外,只需要指定監(jiān)聽端口啟動(dòng)服務(wù)器就可以了。
與讀者做個(gè)約定,下文中服務(wù)器Address都是
192.168.1.11
,監(jiān)聽的端口是8080
。
3.1. 網(wǎng)站部署示例
我們先來部署一個(gè)位于Assets中/web
下的網(wǎng)站:
@Website
public class InternalWebsite extends AssetsWebsite {
public InternalWebsite() {
super("/web");
}
}
因此SD的文件可以刪除也可以增加,所以很方便做一些文件的熱插拔,部署SD卡的網(wǎng)站:
@Website
public class InternalWebsite extends StorageWebsite {
public InternalWebsite() {
super("/sdcard/AndServer/web");
}
}
如上所示,開發(fā)者只需要將網(wǎng)站所在的路徑告訴AndServer
,并添加Website
注解即可,該網(wǎng)站的Html、CSS、JS、其它文件都可以被訪問,例如/web
目錄下有一個(gè)index.html
文件,那么訪問地址就是http://192.168.1.11:8080/
或者http://192.168.1.11:8080/index.html
。
3.2. Http Api開發(fā)示例
在文章開頭我們看了一個(gè)模擬用戶的Http Api,下面我們?cè)黾右粋€(gè)模擬獲取用戶信息的Api:
@RequestMapping("/user")
@RestController
public class UserController {
@PostMapping("/login")
public String login(@RequestParam("account") String account,
@RequestParam("password") String password) {
if(...) {
return "Successful";
}
return "Failed";
}
@GetMapping("/info/{userId}")
public User info(@PathVariable("userId") String userId) {
User user = ...;
return user;
}
}
于是我們得到兩個(gè)地址:
POST http://192.168.1.11:8080/user/login
GET http://192.168.1.11:8080/user/info/uid_001
接下來什么配置都不用做,只需要啟動(dòng)服務(wù)器,這幾個(gè)地址就可以用了。
3.3. 啟動(dòng)服務(wù)器
AndServer.serverBuilder()
.inetAddress(NetUtils.getLocalIPAddress())
.port(8080)
.timeout(10, TimeUnit.SECONDS)
.build()
.start();
如上所示只需要指定要監(jiān)聽的服務(wù)端地址和端口,啟動(dòng)服務(wù)器就可以訪問上面的所有地址了,不需要再做其他配置。
由于篇幅關(guān)系,本文到此結(jié)束,介紹的比較粗略,有興趣的開發(fā)者可以看看項(xiàng)目使用文檔:
https://www.yanzhenjie.com/AndServer
相關(guān)案例查看更多
相關(guān)閱讀
- 云南網(wǎng)站建設(shè)百度官方
- 報(bào)廢車拆解管理系統(tǒng)
- 網(wǎng)站建設(shè)快速優(yōu)化
- 做網(wǎng)站
- 網(wǎng)站建設(shè)選
- 云南省建設(shè)廳網(wǎng)站官網(wǎng)
- 楚雄網(wǎng)站建設(shè)公司
- 報(bào)廢車回收管理軟件
- 網(wǎng)站建設(shè)費(fèi)用
- 區(qū)塊鏈
- uniapp開發(fā)小程序
- 云南網(wǎng)站維護(hù)
- 昆明小程序公司
- 汽車報(bào)廢軟件
- 云南網(wǎng)站建設(shè)制作
- 小程序用戶登錄
- 網(wǎng)站搭建
- 云南網(wǎng)站建設(shè)高手
- 網(wǎng)站建設(shè)制作
- 汽車報(bào)廢管理
- 云南網(wǎng)站建設(shè)公司
- 北京小程序制作
- 網(wǎng)站建設(shè)服務(wù)公司
- 開通微信小程序被騙
- php網(wǎng)站
- 開發(fā)微信小程序
- 云南網(wǎng)絡(luò)公司
- 小程序技術(shù)
- 網(wǎng)站建設(shè)公司網(wǎng)站
- 小程序被騙