安卓后端mysql_后端Spring Boot+前端Android交互+MySQL增删查改(Java+Kotlin实现)
1 前言&概述
這篇文章是基于這篇文章的更新,主要是更新了一些技術棧以及開發工具的版本,還有修復了一些Bug。
本文是SpringBoot+Android+MySQL的增刪查改的簡單實現,用到的技術包括Jackson、OkHttp、bouncycastle、Spring Data JPA。
2 環境
Android 4.1.2
IDEA 2020.3.1
Spring Boot 2.4.2
MySQL 8.0.23
OpenJDK 11
環境準備就略過了,需要的可以參考這里。
3 后端
3.1 新建項目
依賴:
3.2 項目結構
3.3 實體類
@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
private String password;
}
基本的Lombok注解+JPA中的兩個注解:
@Id:標識主鍵
@GeneratedValue:主鍵生成策略,包括四個
主鍵生成策略如下:
GenerationType.TABLE:使用一個特定的數據庫表格來保存主鍵,不依賴外部環境和數據庫的具體實現,但是不能充分利用數據庫特性,一般不會優先使用,且一般配合@TableGenerator使用
GenerationType.SEQUENCE:一些數據庫不支持主鍵自增(如Oracle),這時就可以使用SEQUENCE,只有部分(Oracle/DB2/PostgreSQL)支持序列對象,一般不用于其他數據庫
GenerationType.IDENTITY:一般意義上的主鍵自增長,插入數據時自動給主鍵復制,比如MySQL中的auto_increment
GenerationType.AUTO:主鍵生成策略交給持久化引擎,持久化引擎會根據數據庫在以上三種主鍵策略中選擇其中一種,這是JPA默認的主鍵生成策略
3.4 持久層
繼承CrudRepository,T為實體類,ID為主鍵類型:
@Repository
public interface UserRepository extends CrudRepository {
boolean existsByName(String name);
User findByNameAndPassword(String name,String password);
}
一個需要注意的點是CrudRepository繼承了Repository,而后者有一個叫查詢方法的特性,就是說能根據一些方法中指定的關鍵字去生成對應的SQL,比如第一個方法existsByName,就根據name判斷用戶是否存在,參數為一個String name,返回boolean,具體的關鍵字以及例子參考如下:
3.5 業務層
@Transactional
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class UserService {
private final UserRepository repository;
public boolean exists(User user){
return repository.existsByName(user.getName());
}
public User findByNameAndPassword(User user){
return repository.findByNameAndPassword(user.getName(),user.getPassword());
}
public boolean insert(User user){
repository.save(user);
return true;
}
public boolean update(User user){
if(repository.findById(user.getId()).isEmpty()){
return false;
}
repository.save(user);
return true;
}
public boolean deleteById(int id){
if(!repository.existsById(id)){
return false;
}
repository.deleteById(id);
return true;
}
}
注解解釋如下:
@Transactional:
@Service:標識為業務層,實際效果等價于@Component
@RequiredArgsConstructor:Lombok中的一個注解,主要是為了解決如下的警告:
其他一些根據方法名就知道含義的方法就不解釋了。
3.6 控制層
@RestController
@RequestMapping("/")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class UserController {
private final UserService service;
@PostMapping("sign/in/up")
public ResponseBody signInUp(@RequestBody User user) {
if (service.exists(user)) {
User u = service.findByNameAndPassword(user);
return new ResponseBody(u != null ? ResponseCode.SIGN_IN_SUCCESS : ResponseCode.SIGN_IN_FAILED, u != null ? u.getId() : "");
}
return new ResponseBody(service.insert(user) ? ResponseCode.SIGN_UP_SUCCESS : ResponseCode.SIGN_UP_FAILED, "");
}
@PutMapping("update")
public ResponseBody update(@RequestBody User user) {
return new ResponseBody(service.update(user) ? ResponseCode.UPDATE_SUCCESS : ResponseCode.UPDATE_FAILED, "");
}
@DeleteMapping("delete")
public ResponseBody deleteByName(@RequestParam int id) {
return new ResponseBody(service.deleteById(id) ? ResponseCode.DELETE_SUCCESS : ResponseCode.DELETE_FAILED, "");
}
@GetMapping("test")
public String test() {
return "test";
}
}
注解解釋如下:
@RestController:等價于@ResponseBody+@Controller,@RepsonseBody是直接返回數據的注解(不是默認的視圖名字),而@Controller與@Service類似,查看源碼可知道都是@Component的別名
@RequestMapping:表示該類中的方法中包含的Mapping都以此值開頭
@PostMapping/@PutMapping/@DeleteMapping/@GetMapping:標識處理POST/PUT/Delete/GET請求的路徑,如果類上添加了@RequestMapping,則把路徑拼接在@RequestMapping的后面,比如這里的@GetMapping("test")相當于/test
3.7 響應體+響應碼
響應體:
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class ResponseBody {
private int code;
private Object data;
}
響應碼:
public class ResponseCode {
public static final int SIGN_IN_SUCCESS = 2000;
public static final int SIGN_UP_SUCCESS = 2001;
public static final int UPDATE_SUCCESS = 2002;
public static final int DELETE_SUCCESS = 2003;
public static final int SIGN_IN_FAILED = 3000;
public static final int SIGN_UP_FAILED = 3001;
public static final int UPDATE_FAILED = 3002;
public static final int DELETE_FAILED = 3003;
}
3.8 配置文件
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/userinfo
jpa:
open-in-view: false
hibernate:
ddl-auto: update
數據庫名字以及用戶名密碼請根據自己需要修改,open-in-view這個選項在JPA默認為true,設置為false是為了抑制一個警告,開啟它的含義是在事務外也可以訪問懶加載的數據,這樣可能會引起手動數據源切換失敗的問題,因此設置為false。
ddl-auto: update表示更新數據表,原有數據保留,而且能在沒有創建表的情況下自動創建表。該參數一共有5個設置選項:update、create、create-drop、validate、none,具體區別可以查看這里。
3.9 測試
運行后可以訪問本地的localhost:8080/test會看到如下頁面:
這樣就沒問題了,剩下的需要配合Android端測試。
4 Android端
4.1 新建項目
Android Q+Java。
4.2 依賴+權限
依賴:
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.1'
implementation 'org.bouncycastle:bcprov-jdk15to18:1.68'
implementation "org.projectlombok:lombok:1.18.16"
annotationProcessor 'org.projectlombok:lombok:1.18.16'
權限:
android:usesCleartextTraffic="true"
開啟viewBinding:
buildFeatures{
viewBinding = true
}
4.3 項目結構
4.4 實體類
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class User {
private int id;
private String name;
private String password;
public User(String name, String password) {
this.name = name;
this.password = password;
}
}
4.5 工具類
public class Utils {
private static final Keccak.Digest512 digest512 = new Keccak.Digest512();
public static String encrypt(String origin) {
return new String(Hex.encode(digest512.digest(origin.getBytes(StandardCharsets.UTF_8))));
}
public static String getResponseMessage(int code) {
String message = "";
switch (code) {
case ResponseCode.SIGN_IN_SUCCESS:
message = "登錄成功";
break;
case ResponseCode.SIGN_UP_SUCCESS:
message = "注冊成功";
break;
case ResponseCode.SIGN_IN_FAILED:
message = "用戶名或密碼錯誤";
break;
case ResponseCode.SIGN_UP_FAILED:
message = "注冊失敗";
break;
case ResponseCode.DELETE_FAILED:
message = "刪除失敗";
break;
case ResponseCode.DELETE_SUCCESS:
message = "刪除成功,自動退出";
break;
case ResponseCode.UPDATE_SUCCESS:
message = "更新成功";
break;
case ResponseCode.UPDATE_FAILED:
message = "更新失敗";
break;
case ResponseCode.EMPTY_RESPONSE:
message = "響應體為空";
break;
case ResponseCode.SERVER_ERROR:
message = "服務器錯誤";
break;
case ResponseCode.JSON_SERIALIZATION:
message = "JSON序列化錯誤";
break;
case ResponseCode.EXIT_SUCCESS:
message = "退出成功";
break;
case ResponseCode.REQUEST_FAILED:
message = "請求發送失敗";
break;
case ResponseCode.UNCHANGED_INFORMATION:
message = "未修改信息";
break;
}
return message;
}
public static void showMessage(Context context, Message message) {
Toast.makeText(context, getResponseMessage(message.what), Toast.LENGTH_SHORT).show();
}
}
工具類有三個方法,分別是:
加密:將密碼進行SHA3-512加密,加密后的密碼再發送到后端
獲取對應信息:根據Message獲取對應的提示信息
展示信息:利用Toast展示信息
4.6 響應體+響應碼
響應體:
@NoArgsConstructor
@Setter
@Getter
public class RestResponse {
private int code;
private Object data;
}
響應碼:
public class ResponseCode {
public static final int SIGN_IN_SUCCESS = 2000;
public static final int SIGN_UP_SUCCESS = 2001;
public static final int UPDATE_SUCCESS = 2002;
public static final int DELETE_SUCCESS = 2003;
public static final int SIGN_IN_FAILED = 3000;
public static final int SIGN_UP_FAILED = 3001;
public static final int UPDATE_FAILED = 3002;
public static final int DELETE_FAILED = 3003;
public static final int EMPTY_RESPONSE = 4000;
public static final int SERVER_ERROR = 4001;
public static final int REQUEST_FAILED = 4002;
public static final int JSON_SERIALIZATION = 4003;
public static final int EXIT_SUCCESS = 4004;
public static final int UNCHANGED_INFORMATION = 4005;
}
4.7 請求URL常量
public class NetworkSettings {
private static final String HOST = "192.168.1.8";
private static final String PORT = "8080";
public static final String SIGN_IN_UP = "http://"+ HOST +":"+PORT + "/sign/in/up";
public static final String UPDATE = "http://"+ HOST +":"+PORT + "/update";
public static final String DELETE = "http://"+ HOST +":"+PORT + "/delete";
}
4.8 MainActivity
上一部分代碼吧,剩下的大部分類似,看源碼鏈接即可。
public void signInUp(View view) {
try {
String name = binding.name.getText().toString();
//SHA3-512加密
String password = Utils.encrypt(binding.password.getText().toString());
//構造OkHttp請求Request
Request request = new Request.Builder().url(NetworkSettings.SIGN_IN_UP).post(
//請求體類型為application/json;charset=utf-8,利用了Jackson序列化為JSON
RequestBody.create(mapper.writeValueAsString(new User(name, password)), mediaType)
).build();
//異步POST操作,傳入一個Callback回調
client.newCall(request).enqueue(new Callback() {
//若失敗
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
//請求失敗信息
message.what = ResponseCode.REQUEST_FAILED;
//展示對應信息,注意不能直接使用Toast.make(getApplicationContext(),"message",Toast.LENGTH_SHORT).show()
//因為不是同一個線程,需要使用Handler提交,也就是post()方法,參數為一個線程
handler.post(()->Utils.showMessage(getApplicationContext(),message));
e.printStackTrace();
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
//如果成功
if (response.isSuccessful()) {
//獲取請求體
ResponseBody body = response.body();
//如果響應體不為空
if (body != null) {
//反序列化為響應體,包含了一個響應碼以及數據字段
RestResponse restResponse = mapper.readValue(body.string(), RestResponse.class);
//設置Message
message.what = restResponse.getCode();
//如果登錄成功
if(message.what == ResponseCode.SIGN_IN_SUCCESS){
handler.post(()->{
//存儲用戶id
signInId = (int)restResponse.getData();
//更新UI
binding.update.setVisibility(View.VISIBLE);
binding.delete.setVisibility(View.VISIBLE);
binding.signInUp.setText("退出");
binding.signInUp.setOnClickListener(v->signOut(false));
//保存舊用戶名以及舊密碼在更新的時候使用
oldName = binding.name.getText().toString();
oldPassword = binding.password.getText().toString();
});
}
} else {
//空響應體
message.what = ResponseCode.EMPTY_RESPONSE;
Log.e("RESPONSE_BODY_EMPTY", response.message());
}
} else {
//服務器錯誤
message.what = ResponseCode.SERVER_ERROR;
Log.e("SERVER_ERROR", response.message());
}
//根據Message提示對應信息
handler.post(()->Utils.showMessage(getApplicationContext(),message));
}
});
} catch (JsonProcessingException e) {
message.what = ResponseCode.JSON_SERIALIZATION;
Utils.showMessage(getApplicationContext(),message);
e.printStackTrace();
}
}
這部分是登錄注冊的代碼,還有更新用戶信息以及刪除用戶的代碼,大部分類似。
5 測試
6 注意事項
如果出現了問題某些功能不能正常實現可以參考此處的一些注意事項以及解決方案。
7 源碼
提供了Java+Kotlin兩種實現:
8 參考鏈接
如果覺得文章好看,歡迎點贊。
同時歡迎關注微信公眾號:氷泠之路。
總結
以上是生活随笔為你收集整理的安卓后端mysql_后端Spring Boot+前端Android交互+MySQL增删查改(Java+Kotlin实现)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql查询职位大于3_4、MySQL
- 下一篇: java 类与对象题_Java 类与对象