簡易的伺服器介面開發入門教程

前沿

為了解決伺服器介面開發的問題,因此學習了關於Spring Boot的知識,然後再自己摸索總結後台的開發經驗。所以這篇文章就是面向搞移動開發同時又想了解後台開發的朋友,講解如何使用Spring Boot開發伺服器介面,然後在Android客戶端調用該介面進行數據請求。

Spring Boot特點

  • 創建獨立的Spring應用程式
  • 嵌入的Tomcat,無需部署WAR文件
  • 簡化Maven配置
  • 自動配置Spring
  • 提供生產就緒型功能,如指標,健康檢查和外部配置
  • 絕對沒有程式碼生成並且對XML也沒有配置要求

基本要求

  • 熟悉Java語言
  • 對Java Web開發,Spring框架等有所了解。
  • 會Android開發,熟悉常用的網路請求框架。
  • 會使用IDEA,Android Studio開發工具。
  • 對網路知識有所了解。
  • 擁有JDK 1.8的開發環境。

服務端開發

現在開始進行服務端的介面開發,例子是當客戶端上傳的用戶的昵稱,年齡,性別,服務端返回相關的數據。介面設計如下:

介面地址:// ip address :8080/api/test

返回格式:json

請求方式:http get/post

請求示例:// ip address :8080/api/test?nickname=lake&age=20&gender=male

開始使用IDEA構建項目

一、啟動 IDEA,選擇”Create New Project”。

二、選擇”Spring Initializr”,然後點擊”Next”。

三、這一步填寫好 Group 和 Artifact ,然後點擊”Next”。

四、勾選”Web”依賴,然後點擊”Next”。

五、選擇好項目創建的相關目錄位置,然後點擊”Finish”即可。

六、當進入到主介面可以看到 IDEA 自動生成相關的類和文件。

  • /src/main/java/ 存放項目所有源程式碼目錄
  • /src/main/resources/ 存放項目所有資源文件以及配置文件目錄
  • /src/test/ 存放測試程式碼目錄
  • pom.xml 配置文件

七、先創建兩個Java bean,一個名稱為Info的實體類,用於接收客戶端傳輸的數據,一個名稱為Data的實體類,用於返回數據到客戶端。如下圖所示:

Info類完整程式碼如下:

package com.example.demo.entity;

public class Info {

    private String nickname;
    private String gender;
    private int age;

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public String getNickname() {
        return nickname;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getGender() {
        return gender;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }
}

Data類完整程式碼如下:

package com.example.demo.entity;

public class Data {

    private int code;
    private String result;

    public Data setCode(int code) {
        this.code = code;
        return this;
    }

    public int getCode() {
        return code;
    }

    public Data setResult(String result) {
        this.result = result;
        return this;
    }

    public String getResult() {
        return result;
    }
}

八、再創建一個名稱為ApiController的類,該類裡面分別有get,post,dealWith三個方法。get方法用於接收客戶端的GET請求,post方法用於接收客戶端的POST請求,dealWith方法用於處理客戶端傳輸來數據並返回處理的結果。

get方法會自動把客戶端傳來的表單的數據解析出來再保存到info變數中,該方法的返回值是一個對象時,會默認將對象轉換為Json格式返回。post方法的傳入形參和返回的值的流程差不多,不同的是,POST請求時把請求體的數據解析出來再保存到info變數中,而且請求體的數據格式必須為Json格式。

下面解釋一下ApiController類中的各個註解的作用。
@RestController:處理http請求,返回的數據格式為json格式。

@RequestMapping:配置url映射,可以作用於類和方法上。可以使用method指定GET,POST,DELETE,PUT四種標準請求,默認為GET請求。

@GetMapping:相當於@RequestMapping + RequestMethod.GET。用於GET請求。

@PostMapping:相當於@RequestMapping + RequestMethod.POST。用於POST請求。

使用這些註解配置Url映射,即可獲得你設計的API介面:// ip address :8080/api/test

ApiController類的完整的源碼如下:

package com.example.demo.controller;

import com.example.demo.entity.Data;
import com.example.demo.entity.Info;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(value = "/api")
public class ApiController {

    @GetMapping(value = "/test")
    public Data get(Info info) {
        return dealWith(info);
    }

    @PostMapping(value = "/test")
    public Data post(Info info) {
        return dealWith(info);
    }

    /**
     * @param info  用戶的資訊
     * @return      處理用戶資訊的結果
     */
    private Data dealWith(Info info) {
        String nickname = info.getNickname();
        String gender = info.getGender();
        int age = info.getAge();

        if (StringUtils.isEmpty(nickname)) {
            return new Data().setCode(-1).setResult("Nickname can not be blank.");
        }

        if (StringUtils.isEmpty(gender)) {
            return new Data().setCode(-2).setResult("Gender can not be blank.");
        }else if (gender.equals("male")) {
            gender = "boy";
        }else if (gender.equals("female")) {
            gender = "girl";
        }else {
            return new Data().setCode(-2).setResult("Gender is not legal");
        }

        if (age < 0) {
            return new Data().setCode(-3).setResult("Age can not be less than zero.");
        }

        String result = nickname + "'s age is " + age + " year old, " + "he(she) is a " + gender;
        return new Data().setCode(0).setResult(result);
    }
}

九、最後進行本地測試,點擊啟動按鈕,當操控台輸出「 Completed initialization…… 」的文本,說明該項目啟動成功了,然後打開Microsoft Edge瀏覽器,地址欄中輸入如下url並訪問。

//localhost:8080/api/test?nickname=Lake&gender=male&age=20 

進行GET請求測試時,當請求成功後會看到瀏覽器會顯示一行Json文本,若請求時中填寫的參數不正確,伺服器返回的Json文本會說明錯誤的原因和對應的錯誤碼。

十、簡易的服務端介面開發完成了,把這個Spring Boot項目打包成一系列的jar包,然後上傳到一台已安裝JDK 1.8的伺服器上,打開命令行窗口,輸入命令,”java -jar xxx.jar”,該項目即可啟動,若要後台運行,輸入命令”nohup java -jar xxx.jar &”,因篇幅有限,關於打包和部署到伺服器上的操作步驟,暫時不在本文詳寫了。你可能會問伺服器需要安裝Tomcat嗎?答案是:不需要,因為Spring Boot的項目已內置Tomcat,所以不必自己再安裝Tomcat了。伺服器開發流程到此完畢,接下來到客戶端開發。

客戶端開發

使用Android Studio開發Android項目,相信各位朋友都會熟練創建一個空的Android項目了,所以這裡不再詳述創建項目的步驟了。Android網路請求框架一般有 OkHttp,Retrofit 等,但是本次我使用的是 OkGo 這個網路請求框架,這框架我也是第一次用,先試試看。

一、編寫客戶端程式的布局介面,因為介面的布局比較簡單,所以文章中就不貼出布局文件的程式碼了,介面布局如下圖所示:

二、在AndroidManifest.xml文件中添加聯網的許可權,同時在app模組中的build.gradle文件中添加OkGo的依賴。

AndroidManifest.xml文件中添加聯網許可權的程式碼:

<uses-permission android:name="android.permission.INTERNET"/>

在build.gradle文件中添加依賴的程式碼:

implementation 'com.lzy.net:okgo:3.0.4'

三、在MainActivity類中寫相關的程式碼,initView方法用於初始化布局控制項,request方法用於請求服務端的數據,RequestMethod介面用於選擇請求的方式(GET/POST),字元串常量URL是服務端的介面地址。

MainActivity類的完整程式碼如下:

package com.example.demo;

import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.TextView;

import com.lzy.okgo.OkGo;
import com.lzy.okgo.callback.StringCallback;
import com.lzy.okgo.model.Response;

import java.util.Objects;

public class MainActivity extends AppCompatActivity {

    //伺服器的介面地址
    private final static String URL = "//192.168.43.188:8080/api/test";

    /**
     * 請求的類型
     */
    private interface RequestMethod {
        int GET = 1;
        int POST = 2;
    }

    private EditText activity_main_nickname_et;
    private EditText activity_main_age_et;
    private RadioButton activity_main_male_rb;
    private RadioButton activity_main_female_rb;
    private TextView activity_main_log_tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    /**
     * 初始化布局
     */
    private void initView() {
        activity_main_nickname_et = findViewById(R.id.activity_main_nickname_et);
        activity_main_age_et = findViewById(R.id.activity_main_age_et);
        activity_main_male_rb = findViewById(R.id.activity_main_male_rb);
        activity_main_female_rb = findViewById(R.id.activity_main_female_rb);
        activity_main_log_tv = findViewById(R.id.activity_main_log_tv);

        //軟鍵盤管理
        final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        final View view = getWindow().peekDecorView();
        Objects.requireNonNull(imm);

        findViewById(R.id.activity_main_get_btn)
                .setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
                        request(RequestMethod.GET);
                    }
                });

        findViewById(R.id.activity_main_post_btn)
                .setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
                        request(RequestMethod.POST);
                    }
                });
    }

    /**
     * 數據請求
     * @param requestType
     */
    private void request(final int requestType) {
        String nickname = activity_main_nickname_et.getText().toString();
        String age = activity_main_age_et.getText().toString();
        String gender = (activity_main_male_rb.isChecked()) ? "male" : "female";

        if (requestType == RequestMethod.GET) {
            OkGo.<String>get(URL)
                    .params("nickname", nickname)
                    .params("gender", gender)
                    .params("age", age)
                    .execute(new StringCallback() {
                        @Override
                        public void onSuccess(Response<String> response) {
                            String log = "GET請求:\n" + response.body();
                            activity_main_log_tv.setText(log);
                        }
                    });
        }else if (requestType == RequestMethod.POST) {
            OkGo.<String>post(URL)
                    .params("nickname", nickname)
                    .params("gender", gender)
                    .params("age", age)
                    .execute(new StringCallback() {
                        @Override
                        public void onSuccess(Response<String> response) {
                            String log = "POST請求:\n" + response.body();
                            activity_main_log_tv.setText(log);
                        }
                    });
        }
    }
}

四、客戶端的程式碼大概就是這樣,現在來測試一下客戶端與服務端的交互。本地測試,先保證電腦和手機連接了同一個網路並且電腦需要打開8080埠,例如連接同一個WiFi,或者手機開熱點,電腦連接手機的熱點。 然後獲取電腦的IP地址,再把客戶端的程式碼中MainActivity類的URL常量的IP地址改為你電腦(伺服器)的IP地址。把IDEA中的服務端程式啟動,再把客戶端Demo安裝到手機上,就可以體驗到自己親手設計的介面了。效果圖如下:

結語

簡易伺服器介面開發入門教程已經寫完了,文章沒有涉及到資料庫的內容,還有和Spring Boot密切相關的maven也沒有提起,就是為了讓文章寫得更通俗易懂。這篇文章只能讓你了解一下簡單的介面開發過程,如果要學會使用Spring Boot開發實用的後台介面,還是需要學好基礎知識,再找一本與Spring Boot相關的書籍進行學習。因為我的專業主要是搞網路相關,而不是搞開發的,搞開發是課餘時間的興趣愛好,所以文章有寫的不妥之處,望大家指正和諒解。