flutter数据请求

首先,简单介绍一下spring boot的配置和连接数据库获取数据(在Log in with Atlassian account 案例基础上进行修改)。

spingboot目录结构:

 

SpingMVCConfig.java:

 

(由于从Intellij IDEA中复制的代码在这里粘贴,结构会乱,所以这里用代码截图)

Product.java:

 

ApiController.java:

package com.example.odata.controller;

import com.example.odata.dao.HeroesDao;
import com.example.odata.entity.Hero;
import com.example.odata.entity.Product;
import com.example.odata.repository.ProductsRepository;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.beans.PropertyDescriptor;
import java.util.*;

@RestController
@RequestMapping("/api")
public class ApiController
{
@Autowired
private ProductsRepository prodectsRepository;

@GetMapping(value = "/Products",
		produces = "application/json; charset=UTF-8")
public List<Product> queryAllFromDB()
{
	return prodectsRepository.findAll();
}

@GetMapping(value = "/Products/{id}",
		produces = "application/json; charset=UTF-8")
public Optional<Product> queryOneFromDB(@PathVariable("id") Integer id)
{
	return prodectsRepository.findById(id);
}

@PostMapping("/Products")
public boolean insertToDB(@RequestBody Product data)
{
	prodectsRepository.save(data);
	return true;
}

@PutMapping("/Products")
public boolean updateToDB(@RequestBody Product data)
{
	prodectsRepository.save(data);
	return true;
}
@PatchMapping("/Products/{id}")
public boolean updatePartToDB(@PathVariable("id") Integer id,
@RequestBody Product data)
{
if (prodectsRepository.existsById(id))
{
Product oldData = prodectsRepository.getById(id);
data.setProductid(id);
		BeanUtils.copyProperties(data, oldData, getNullPropertyNames(data));

		prodectsRepository.save(oldData);
		return true;
	}

	return false;
}


@DeleteMapping("/Products/{id}")
public boolean deleteToDB(@PathVariable("id") Integer id)
{
	prodectsRepository.deleteById(id);
	return true;
}



@Autowired
private HeroesDao heroesDao;

@GetMapping(value = "/heroes", 
		produces = "application/json; charset=UTF-8")
public List<Hero> queryAllByDao()
{
	return heroesDao.findAll();
}

@GetMapping(value = "/heroes/{id}", 
		produces = "application/json; charset=UTF-8")
public Hero queryOneByDao(@PathVariable("id") int id)
{
	return heroesDao.findById(id);
}

@PostMapping("/heroes")
public Hero insertByDao(@RequestBody Hero data)
{
	heroesDao.insert(data);
	return data;
}

@PutMapping("/heroes")
public boolean updateByDao(@RequestBody Hero data)
{
	heroesDao.update(data);
	return true;
}

@DeleteMapping("/heroes/{id}")
public boolean deleteByDao(@PathVariable("id") int id)
{
	heroesDao.deleteById(id);
    return true;
}
private List<Map<String, Object>> dataList;

public ApiController()
{
	dataList = new ArrayList<Map<String, Object>>();
	
	Map<String, Object> data;
	
	data = new HashMap<String, Object>();
	data.put("id", 1);
	data.put("title", "测试数据aaa");
	data.put("subtitle", "aaa");
	dataList.add(data);
	
	data = new HashMap<String, Object>();
	data.put("id", 2);
	data.put("title", "测试数据bbb");
	data.put("subtitle", "bbb");
	dataList.add(data);
	
	data = new HashMap<String, Object>();
	data.put("id", 3);
	data.put("title", "测试数据ccc");
	data.put("subtitle", "ccc");
	dataList.add(data);    	

	data = new HashMap<String, Object>();
	data.put("id", 4);
	data.put("title", "测试数据ddd");
	data.put("subtitle", "ddd");
	dataList.add(data);		
}

@GetMapping(value = "/test", 
		produces = "application/json; charset=UTF-8")
public List<Map<String, Object>> queryAllFromMock()
{
    return dataList;
}

@GetMapping(value = "/test/{id}", 
		produces = "application/json; charset=UTF-8")
public Map<String, Object> queryOneFromMock(@PathVariable("id") Integer id)
{
	for (Map<String, Object> data : dataList)
	{
		if (data.get("id") == id)
		{
			return data;
		}
	}

    return new HashMap<String, Object>();
}

@PostMapping("/test")
public boolean insertToMock(@RequestBody Map<String, Object> data)
{
	dataList.add(data);
	return true;
}

@PutMapping("/test")
public boolean updateToMock(@RequestBody Map<String, Object> data)
{
	for (int i = 0; i < dataList.size(); i++)
	{
		if (dataList.get(i).get("id") == data.get("id"))
		{
			dataList.set(i, data);
			return true;
		}
	}

	return false;
}

@PatchMapping("/test/{id}")
public boolean updatePartToMock(@PathVariable("id") Integer id, 
		@RequestBody Map<String, Object> data)
{
	for (int i = 0; i < dataList.size(); i++)
	{
		if (dataList.get(i).get("id") == id)
		{
			Set<String> keys = data.keySet();
			
			for (String key : keys)
			{
				dataList.get(i).put(key, data.get(key));
			}

			return true;
		}
	}
	
	return false;
}

@DeleteMapping("/test/{id}")
public boolean deleteToMock(@PathVariable("id") Integer id)
{
	for (Map<String, Object> data : dataList)
	{
		if (data.get("id") == id)
		{
			dataList.remove(data);
			return true;
		}
	}
	
    return false;
}

public static String[] getNullPropertyNames (Object source) 
{
    final BeanWrapper src = new BeanWrapperImpl(source);
    PropertyDescriptor[] pds = src.getPropertyDescriptors();
 
    Set<String> emptyNames = new HashSet<>();
    for(PropertyDescriptor pd : pds) 
    {
        Object srcValue = src.getPropertyValue(pd.getName());	        
        if (srcValue == null) 
        {
            emptyNames.add(pd.getName());
        }
    }
    
    String[] result = new String[emptyNames.size()];
    return emptyNames.toArray(result);
}

ProductsRepository.java:

 

Spring Boot项目的pom.xml里需要加上下面这两个依赖:

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

然后在application.properties里配上数据库的连接信息:

spring.jpa.hibernate.ddl-auto=update
spring.datasource.url = jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai
spring.datasource.username = root
spring.datasource.password = ******
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver

spring.jpa.show-sql=true

因为我这边数据库用的是mySQL,需要在pom.xml里加上下面这两个依赖:

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

 

如果觉得在Entity里给所有属性写getter和setter函数麻烦的话,可以在Entity类上加@Data注解,然后在pom.xml里加上下面这个依赖:

<dependency>
 <groupId>org.projectlombok</groupId>
 <artifactId>lombok</artifactId>
 <optional>true</optional>
</dependency>

想要@Data注解起效还需要在Spring Tool Suite目录下放一个lombok.jar包,并在SpringToolSuite4.ini里加上下面这句话:
-javaagent:D:\Tools\SpringToolSuite\sts\lombok.jar


现在我们要将flutter项目通过spring boot服务器获取数据库数据并渲染到页面。

http请求

http:是Dart.dev提供的第三方类库,地址:https://pub.dev/packages/http

需要先在pubspec.yaml里添加类库应用:

导入:

获取数据:

 _getData() async {
    var apiUrl = Uri.parse('http://192.168.1.7:8081/api/Products');
    var response = await http.get(apiUrl);
    if (response.statusCode == 200) {
      setState(() {
        _list = json.decode(response.body);
            print(_list);
      });
    }
  }

同时要在全局定义_list接受数据List _list = [];

在页面初始化时调用_getData()方法:

 @override
  void initState() {
    super.initState();
    _getData();
  }

此时如果请求成功控制台会打印数据:

 

通过ListView渲染到页面:

 @override
  Widget build(BuildContext context) {
    String inputValue = '';
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: _list.isNotEmpty
          ? ListView.builder(
              itemCount: _list.length,
              itemBuilder: (BuildContext context, int index) {
                return ListTile(
                  title: Text(_list[index]["productid"].toString(),
                      style: const TextStyle(fontSize: 18.0)),
                  subtitle: Text(_list[index]["productname"]),
                  leading: const Icon(Icons.people, color: Colors.blue),
                  trailing: InkWell(
                    child: const Icon(Icons.delete_outline, color: Colors.red),
                    onTap: () {
                    },
                  ),
                  },
                );
              },
            )
          : const Text(""),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

post请求:

给页面右下角按钮FloatingActionButton的点击事件里添加一个对话框,当点击按钮是打开对话框:

showDialog<String>(
            context: context,
            barrierDismissible: false,
            builder: (BuildContext context) {
              return AlertDialog(
                title: const Text('请输入昵称'),
                content: SingleChildScrollView(
                  child: ListBody(
                    children: <Widget>[
                      CupertinoTextField(
                        placeholder: '请输入昵称',
                        onChanged: (value) {
                          inputValue = value;
                        },
                      )
                    ],
                  ),
                ),
                actions: <Widget>[
                  CupertinoDialogAction(
                    child: const Text('取消'),
                    onPressed: () {
                      Navigator.pop(context);
                    },
                  ),
                  CupertinoDialogAction(
                    child: const Text('确定'),
                    onPressed: () {
                      print(inputValue);
                      add(inputValue, () => {Navigator.pop(context)});
                    },
                  )
                ],
              );
            },
          ).then((val) {
            print(val);
          });
}

通过onChanged方法获取输入框的值,并在点确定按钮时将值作为参数传给add()方法:

add(e, callBack) async {
    var apiUrl = Uri.parse('http://192.168.1.7:8081/api/Products');
    var data = jsonEncode({"productname": e});
    var response = await http.post(apiUrl,
        headers: {"Content-Type": "application/json"}, body: data);
    print(response.body);
    if (response.body == "true") {
      _getData();
      callBack();
    }else {
      print("请求失败");
    }
  }

add()方法会调用post请求并将参数传给后端,如果请求成功就会重新获取数据渲染页面并退回到上一个页面。


版权声明:本文为m0_65503310原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。