흠,, 요즘 Flutter 에 관심이 생겨서 만들어보려고 한다
그런데 앱을 구현하면서 FireBase로만 데이터를 저장해봤지,
MYSQL,ORACLE 등의 DB에는 저장을 못해봐서 REST API를 이용해서 한번 넣어보자.

import 'package:flutter/material.dart';
import 'package:flutter_application_1/screen/screen_home.dart';
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
home : HomeScreen(),
)
);
}
main.dart에 바로 작성 안하고 homescreen.dart에 작성하고 메인으로 불러온다.
class _HomeScreenState extends State<HomeScreen> {
final _valueList = ['KT', 'SKT', 'LG'];
var _selectedValue = 'KT';
final TextEditingController _phoneNumberController = TextEditingController();
final TextEditingController _nameController = TextEditingController();
void dispose() {
_phoneNumberController.dispose();
_nameController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'입력한 정보가 맞다면 \n아래 확인 버튼을 눌러주세요',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.w600,
),
),
SizedBox(
height: 40,
),
Text(
"휴대폰 번호",
textAlign: TextAlign.start,
style: TextStyle(
color: Colors.grey,
),
),
TextFormField(
controller: _phoneNumberController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.blue),
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color.fromARGB(15, 55, 55, 55)),
)
),
cursorColor: Colors.transparent,
),
SizedBox(
height: 20,
),
Text(
"통신사",
textAlign: TextAlign.start,
style: TextStyle(
color: Colors.grey,
),
),
SizedBox(
width: double.infinity, // DropdownButton을 텍스트 필드의 너비와 일치시킵니다.
child: DropdownButton(
isExpanded: true, // 버튼이 가능한 최대 너비를 가집니다.
value: _selectedValue,
items: _valueList.map(
(value) {
return DropdownMenuItem(
value: value,
child: Text(value),
);
},
).toList(),
onChanged: (value) {
setState(() {
_selectedValue = value.toString();
});
},
),
),
const SizedBox(
height: 20,
),
Text('이름',
style: TextStyle(
color: Colors.grey,
),),
SizedBox(
child: TextFormField(
controller: _nameController,
keyboardType: TextInputType.name,
decoration: const InputDecoration(
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.blue),
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color.fromARGB(15, 55, 55, 55)),
)
),
cursorColor: Colors.transparent,
),
),
SizedBox(height: (20),),
ElevatedButton(onPressed: () {
sendDataToServer(
_phoneNumberController.text,
_selectedValue,
_nameController.text,
);
}, child: Text('확인',style: TextStyle(color: Colors.white),),
style: ElevatedButton.styleFrom(
backgroundColor: Color.fromARGB(255,41, 119, 243),
minimumSize: Size(double.infinity,50),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)
)
),
)
],
),
),
);
}
하면서 느낀거지만 html 에 익숙해져있던지라 화면을 구성하는데 어려움이 많이 느껴졌다..
아마 이렇게 짜는게 아닌데,, 잘못짜서 이렇게 길게 나온거 같은데
고수님이 혹시라도 이 글을 보시고 조언해주셨으면 좋겠다...

어찌됐건 일단 완성,,,
일단 화면은 만들어졌고 해당 TextField 에 값을 입력하고
확인 버튼을 누르면 내가 만든 MYSQL 테이블에 입력값들이 저장이 되어야한다!
@RestController
@RequestMapping("/")
public class MemberCotroller {
private final MemberService memberService;
public MemberCotroller(MemberService memberService) {
this.memberService = memberService;
}
@PostMapping("/register")
public ResponseEntity<String> register(@RequestBody Member member) {
boolean exists = memberService.existsByName(member.getName());
boolean result = memberService.createMember(member);
if(result) {
return ResponseEntity.ok("{\"message\": \"성공했습니다.\"}");
} else {
if(exists) {
return ResponseEntity.badRequest().body("{\"error\": \"duplicate_name\"}");
}
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("{\"error\": \"internal_error\"}");
}
}
}
우선 백엔드쪽도 새로운 걸 도전해보고 싶어서 JPA를 사용하기로 했다.
@RestController를 만들어주고
post 방식으로 보낼거기때문에 @PostMapping("/register)로 구현해준다.
성공하면 "성공했습니다"를 응답하고 실패하면 500에러가 응답할 것이고,
중복된 아이디가 있다면, duplicate_name을 응답하도록 했다.
자 그럼 다시 프론트 쪽에서 데이터 전송 로직을 만들어주자
Future<void> sendDataToServer(String phoneNumber, String telecom, String name) async{
final url = Uri.parse('http://내 아이피:8080/register');
final response = await http.post(
url,
headers: <String,String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{
'phoneNumber' : phoneNumber,
'telecom' : telecom,
'name' : name,
}),
);
if(response.statusCode == 200) {
print('데이터 전송 성공!');
showDialog(context: context,
builder: (BuildContext context){
return AlertDialog(
title: Text(""),
content: Text("성공적으로 가입되었습니다"),
actions: <Widget>[
FloatingActionButton(onPressed: (){
Navigator.of(context).pop();
},
child: Text("확인"),)
],
);
}
);
}else {
print('실패했습니다. ${response.statusCode}' );
print(response.body);
final responseData = json.decode(response.body);
if(responseData['error'] == 'duplicate_name') {
showDialog(context: context,
builder: (BuildContext context){
return AlertDialog(
title: Text("실패"),
content: Text('이미 존재하는 아이디입니다,'),
actions: <Widget>[
ElevatedButton(onPressed: (){
Navigator.of(context).pop();
},
child: Text("확인"),)
],
);
});
}
성공하면 "성공적으로 가입되었습니다" 다이얼로그를 띄워주고,
중복 된 이름을 입력하면 "이미 존재하는 이름입니다" 라고 띄워준다.
(그냥 중복체크 다이얼로그를 띄워보고 싶어 그냥 이름에다가 unique key 값을 적용했다)

파이어베이스에다가 앞단에서 바로 넣는게 아닌
API로 백엔드 쪽으로 데이터를 보내서 저장하는건 처음해보았는데,,
개린이다보니 프론트 백엔드 구분이 잘안되는 상태였는데,
아직 확실히 이해 못했지만 조금은 어떤 느낌으로 구분하는지 알게 된 것 같다.
이런식으로 프론트, 백엔드 둘다 할 줄 알면 풀스택 개발자가 되는건가?..
어렵지만 쉽게 설명해주셔서 감사합니다 :)