@[TOC]

1.概述

使用spring boot作为后端框架与Android端配合mysql进行基本的交互,包含了最基本的增删查改功能.

2.开发环境

win10

IDEA

tomcat9.0.27

mysql8.0.17

spring boot

3.后端

(1)新建一个spring boot项目

(2)Entity

新建User类作为实体类:

package com.test;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

这里其实使用的是(1)中的代码,里面有详细的解释.

(3)Repository

新建UserRepository去实现增删查改:

package com.test;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@Repository
public interface UserRepository extends CrudRepository
{
@Query(value = "select * from user where name = ?1",nativeQuery = true)
public List findByName(String name);
@Modifying
@Query(value = "delete from user where name = ?1",nativeQuery = true)
public int deleteByName(String name);
}

由于CrudRepository中已经包含了"增"与"改",所以按需要实现自己的"查"与"删"即可.

CrudRepository的api很简单,官方文档在这里.

"增"使用save即可,参数为实体类

"删"使用deleteById,通过主键删除,若不想通过主键删除可以自己编写sql,像上面一样

"查"使用findAll或findById,自定义查找的话需要自己编写sql.

"改"也可使用save,注意需要设置主键.

@Query用于设置sql,nativeQuery表示使用原生sql.

(4)Service

新建一个MainService.java

package com.test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.util.List;
@Transactional
@Service
public class MainService {
@Autowired
private UserRepository userRepository;
public Iterable getAllUsers()
{
return userRepository.findAll();
}
public List findByName(String name)
{
return userRepository.findByName(name);
}
public boolean add(String name)
{
User user = new User();
user.setName(name);
userRepository.save(user);
return true;
}
public boolean modify(Integer id,String name)
{
User user = new User();
user.setName(name);
user.setId(id);
userRepository.save(user);
return true;
}
public boolean deleteByName(String name)
{
return userRepository.deleteByName(name) != 0;
}
}

getAllUsers()返回所有行,Iterable类型

findByName()根据name返回所有name相同的行.

add直接使用了save,由于save返回的是实体类,原本的代码是这样写的:

return userRepository.save(user) != null;

Android studio和mysql用springboot android与springboot交互_spring

但是文档说了不会为null,所以只能强制返回true了.

modify使用了id与name作为参数,新建一个user,将其作为setter的参数,然后交给save.

deleteByName使用了自定义的删除函数,返回的是int,在UserRepository中这个int代表sql影响的行数,删除成功则行数不为0,删除失败,或者没有这行数据则行数为0.因此将返回值与0进行比较.

(5)Controller

package com.test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Controller
@RequestMapping(path = "/demo")
public class MainController {
@Autowired
private MainService mainService;
@GetMapping(path = "/getAll")
public @ResponseBody Iterable getAllUsers()
{
return mainService.getAllUsers();
}
@PostMapping(path = "/get")
public @ResponseBody List findByName(String name)
{
return mainService.findByName(name);
}
@PostMapping(path = "/add")
public @ResponseBody boolean add(@RequestParam String name)
{
return mainService.add(name);
}
@PostMapping(path = "/modify")
public @ResponseBody boolean modify(@RequestParam Integer id,@RequestParam String name)
{
return mainService.modify(id,name);
}
@PostMapping(path = "/delete")
public @ResponseBody boolean deleteByName(@RequestParam String name)
{
return mainService.deleteByName(name);
}
}

Controller主要就是几个注解,除了getAllUsers使用Get外,其他的都是用Post.另外就是路径设置,直接在path中设置即可.

后端的话到这里就基本完成了,剩下的打包部署操作就…

4.前端

什么新建工程之类的就不说了.

直接上MainActivity:

package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Looper;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.alibaba.fastjson.JSONArray;
import com.example.myapplication.model.dao.*;
import com.example.myapplication.model.entity.*;
import java.io.IOException;
import java.util.List;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button register = findViewById(R.id.register);
register.setOnClickListener(
v ->
{
new Thread(()-> {
OkHttpClient okHttpClient = new OkHttpClient();
String name = ((EditText) findViewById(R.id.name)).getText().toString();
FormBody formBody = new FormBody.Builder().add("name", name).build();
Request request = new Request.Builder()
.url(Constant.ADD)
.post(formBody)
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
Looper.prepare();
if (Boolean.parseBoolean(response.body().string()))
{
Toast.makeText(this, "注册成功", Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(this, "注册失败", Toast.LENGTH_SHORT).show();
}
Looper.loop();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
);
Button login = findViewById(R.id.login);
login.setOnClickListener(
v ->
{
new Thread(()-> {
OkHttpClient okHttpClient = new OkHttpClient();
String name = ((EditText) findViewById(R.id.name)).getText().toString();
FormBody formBody = new FormBody.Builder().add("name", name).build();
Request request = new Request.Builder()
.url(Constant.GET)
.post(formBody)
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
List users = JSONArray.parseArray(response.body().string(),User.class);
Looper.prepare();
if(users.size() == 0)
{
Toast.makeText(this,"登录失败",Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(this,"登录成功",Toast.LENGTH_SHORT).show();
}
Looper.loop();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
);
Button delete = findViewById(R.id.delete);
delete.setOnClickListener(
v ->
{
new Thread(()-> {
OkHttpClient okHttpClient = new OkHttpClient();
String name = ((EditText) findViewById(R.id.name)).getText().toString();
FormBody formBody = new FormBody.Builder().add("name", name).build();
Request request = new Request.Builder()
.url(Constant.DELETE)
.post(formBody)
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
Looper.prepare();
if (Boolean.parseBoolean(response.body().string()))
{
Toast.makeText(this, "删除成功", Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(this, "删除失败", Toast.LENGTH_SHORT).show();
}
Looper.loop();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
);
Button modify = findViewById(R.id.modify);
modify.setOnClickListener(
v ->
{
new Thread(()-> {
OkHttpClient okHttpClient = new OkHttpClient();
String name = ((EditText) findViewById(R.id.name)).getText().toString();
String id = ((EditText)findViewById(R.id.id)).getText().toString();
FormBody formBody = new FormBody.Builder()
.add("name", name)
.add("id",id)
.build();
Request request = new Request.Builder()
.url(Constant.MODIFY)
.post(formBody)
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
Looper.prepare();
if (Boolean.parseBoolean(response.body().string()))
{
Toast.makeText(this, "修改成功", Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(this, "修改失败", Toast.LENGTH_SHORT).show();
}
Looper.loop();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
);
}
}
(1)增
OkHttpClient okHttpClient = new OkHttpClient();
String name = ((EditText) findViewById(R.id.name)).getText().toString();
FormBody formBody = new FormBody.Builder().add("name", name).build();
Request request = new Request.Builder()
.url(Constant.ADD)
.post(formBody)
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
Looper.prepare();
if (Boolean.parseBoolean(response.body().string()))
{
Toast.makeText(this, "注册成功", Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(this, "注册失败", Toast.LENGTH_SHORT).show();
}
Looper.loop();
} catch (IOException e) {
e.printStackTrace();
}

使用okhttp,通过FormBody设置参数,然后创建Request通过OkHttpClient发送.

由于后端"增"的方法返回的是一个true,因此这里将response.body().string()转换成boolean判断是否操作成功.

稍微提一下,

Looper.prepare();
Looper.loop();

这两行可以在非UI线程中使用Toast.

(2)删

OkHttpClient okHttpClient = new OkHttpClient();
String name = ((EditText) findViewById(R.id.name)).getText().toString();
FormBody formBody = new FormBody.Builder().add("name", name).build();
Request request = new Request.Builder()
.url(Constant.DELETE)
.post(formBody)
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
Looper.prepare();
if (Boolean.parseBoolean(response.body().string()))
{
Toast.makeText(this, "删除成功", Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(this, "删除失败", Toast.LENGTH_SHORT).show();
}
Looper.loop();
} catch (IOException e) {
e.printStackTrace();
}

删这部分也是差不多的,就是改一下url,然后…然后没有了…好像很简单的样子?

(3)查

OkHttpClient okHttpClient = new OkHttpClient();
String name = ((EditText) findViewById(R.id.name)).getText().toString();
FormBody formBody = new FormBody.Builder().add("name", name).build();
Request request = new Request.Builder()
.url(Constant.GET)
.post(formBody)
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
List users = JSONArray.parseArray(response.body().string(),User.class);
Looper.prepare();
if(users.size() == 0)
{
Toast.makeText(this,"登录失败",Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(this,"登录成功",Toast.LENGTH_SHORT).show();
}
Looper.loop();
} catch (IOException e) {
e.printStackTrace();
}

查这里注意一下后端返回的是List,这里借助阿里的fastjson转换成List.

List users = JSONArray.parseArray(response.body().string(),User.class);

然后判断有没有的话就判断长度是否为0即可.

(4)改

OkHttpClient okHttpClient = new OkHttpClient();
String name = ((EditText) findViewById(R.id.name)).getText().toString();
String id = ((EditText)findViewById(R.id.id)).getText().toString();
FormBody formBody = new FormBody.Builder()
.add("name", name)
.add("id",id)
.build();
Request request = new Request.Builder()
.url(Constant.MODIFY)
.post(formBody)
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
Looper.prepare();
if (Boolean.parseBoolean(response.body().string()))
{
Toast.makeText(this, "修改成功", Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(this, "修改失败", Toast.LENGTH_SHORT).show();
}
Looper.loop();
} catch (IOException e) {
e.printStackTrace();
}

改的话只需一个额外的ID参数,在FormBody中add一个即可,不难.

(5)界面

xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
android:id="@+id/delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="280dp"
android:layout_marginTop="404dp"
android:text="删除"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
android:id="@+id/register"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="293dp"
android:text="注册"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
android:id="@+id/modify"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="404dp"
android:text="修改"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
android:id="@+id/name"
android:layout_width="336dp"
android:layout_height="50dp"
android:layout_marginStart="32dp"
android:layout_marginTop="192dp"
android:layout_marginEnd="43dp"
android:ems="10"
android:hint="请输入姓名"
android:inputType="textPersonName"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
android:id="@+id/id"
android:layout_width="336dp"
android:layout_height="50dp"
android:layout_marginStart="32dp"
android:layout_marginTop="112dp"
android:layout_marginEnd="43dp"
android:ems="10"
android:hint="请输入id"
android:inputType="textPersonName"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
android:id="@+id/login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="293dp"
android:layout_marginEnd="43dp"
android:text="登录"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
界面不详细说了,不难.

(6)依赖与其他

Android studio和mysql用springboot android与springboot交互_spring

注意一下依赖,还有设置java8.

(7)网络权限

这个作者之前的文章有说.

请看这里.

5.测试

这是"原本的"数据库.

没办法为了测试.

Android studio和mysql用springboot android与springboot交互_spring

注册一个.

Android studio和mysql用springboot android与springboot交互_spring

看看数据库:

Android studio和mysql用springboot android与springboot交互_spring

Android studio和mysql用springboot android与springboot交互_spring

试试登录一个不存在的.

Android studio和mysql用springboot android与springboot交互_spring

修改:

Android studio和mysql用springboot android与springboot交互_spring

Android studio和mysql用springboot android与springboot交互_spring

Android studio和mysql用springboot android与springboot交互_spring

最后是删除:

Android studio和mysql用springboot android与springboot交互_spring

Android studio和mysql用springboot android与springboot交互_spring

删除一个不存在的会删除失败.

Android studio和mysql用springboot android与springboot交互_spring

6.源码