2018년 2월 6일 화요일

[자마린강좌 동영상] 자마린 앱에서 스프링프레임워크/스프링부트 RESTful기반 웹서비스 Call 실습



[자마린교육/자마린실습]자바,스프링프레임워크(스프링부트) RESTful 웹서비스 구현 실습,자마린에서 스프링 웹서비스를 호출하고 응답 JSON을 받아 XAML 데이터 바인딩을 이용하여 휴대폰 화면에 출력하는 실습_자마린학원 from 탑크리에듀(구로디지털단지역3번출구 2분거리)

(자마린교육)자마린 앱에서 스프링프레임워크/스프링부트 RESTful기반 웹서비스 Call 실습, JSON 파싱하기[웹서비스는 자바,스프링으로 모바일 앱은 자마린으로!]
n  웹은 자바스프링 프레임워크를 기반으로 구축된 곳이 많다왜냐 하면 성능도 좋고 데이터베이스를 다루기에는 용이하기 때문이다. (스프링 프레임워크 마이바티스, Spring Data JPA, ORM 기술 등)
n  자마린 앱에서 원격의 오라클, MS-SQL, MySQL등의 DB에 직접 접속하여 개발하고 싶은 개발자도 있겠지만 이는 적절하지 못한 방법이며 지원 역시 빈약 하기 때문에 문제에 직면할 확률이 높다웹서비스를 만들고 이를 자마린 앱 에서 호출하는 것이 현명할 것 같다.
n  닷넷 기반의 자마린 앱 실습 이지만 스프링프레임워크(스프링 부트기반으로 RESTful WebService를 만들고 이를 자마린 앱 응용프로그램에서 호출하여 결과(응답)를 JSON을 받아 파싱하여 데이터 바인딩을 이용하여 휴대폰 화면에 출력해보자(닷넷 개발자 이지만 이번 기회에 자바 스프링 프레임워크 MVC기반의 RESTful WebService를 경험해 보자별것 아니다.)
n  자바스프링 프레임워크(스프링부트기반으로 간단히 RESTful 기반 웹서비스를 만드는데스프링의 레스트컨트롤러(RestController)를 이용하여 CRUD 기능의 컨트롤러, DAO클래스를 만들고 브라우저에서 먼저 테스트를 한다이것이 확인 되면 Xamarin.Forms로 앱을 만들어 안드로이드 폰(또는 에뮬레이터)을 통해 웹서비스를 호출하는 CRUD를 테스트 하는 실습이다.
n  CRUD 전체 기능을 테스트 하는 것은 여러분들께 맡기고 본 실습에서는 전체 사원데이터 검색한명의 사원 검색하는 정도를 구현해 보기로 한다.
n  스프링 프레임워크(스프링부트)에서 RESTFule기반으로 구현한 실행화면을 먼저 보자.
n  [전체 사원 조회]
n  한명의 사원 조회

n  자바스프링쪽 실습은 Spring Tool Suite(STS)에서 하는데 JDK가 설치되어야 하며구글에서 “STS Download”라고 입력하면 다운받아서 압축풀고 간단하게 실행 할 수 있다.
n  STS를 실행하여 File >> New >> Project >> Spring Stater Project(스프링 부트)를 선택.

n  다음화면에서 Web >> Web 선택 후 Finish 클릭.

n  com.example.demo 패키지에 Emp.java, EmpDAO.java, EmpController.java 3개의 파일을 생성하자.
n  [Emp.java]
package com.example.demo;

public class Emp {
   private Long empno;
   private String ename;
   private Long sal;
   private String job;

   public Emp(Long empno, String ename, Long sal, String job) {
         this.empno = empno;
         this.ename = ename;
         this.sal = sal;
         this.job = job;
   }

   public Long getEmpno() {
         return empno;
   }

   public void setEmpno(Long empno) {
         this.empno = empno;
   }

   public String getEname() {
         return ename;
   }

   public void setEname(String ename) {
         this.ename = ename;
   }

   public Long getSal() {
         return sal;
   }

   public void setSal(Long sal) {
         this.sal = sal;
   }

   public String getJob() {
         return job;
   }

   public void setJob(String job) {
         this.job = job;
   }
}

n  [EmpDAO.java]
package com.example.demo;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Repository;

@Repository
public class EmpDAO {
   private static List<Emp> emps;
   {
         emps = new ArrayList<Emp>();
         emps.add(new Emp(1001L, "TopCredu", 6000L, "CLERK"));
         emps.add(new Emp(1002L, "Jhon Denver", 7000L, "SALESMAN"));
         emps.add(new Emp(1003L, "Karl Luice", 8000L, "MANAGER"));
         emps.add(new Emp(1004L, "Chanho Park", 7000L, "SALESMAN"));
         emps.add(new Emp(1005L, "Phile Migalon", 8000L, "MANAGER"));        
         emps.add(new Emp(1006L, "Jhon Smith", 7500L, "SALESMAN"));
         emps.add(new Emp(1007L, "OracleJavaCommunity", 6800L, "CLERK"));
         emps.add(new Emp(1008L, "Ojc.Asia", 7200L, "CLERK"));
   }
  
   public List<Emp> getEmps() {
         return emps;
   }
  
   public Emp getEmp(Long empno) {
         for(Emp e : emps) {
               if (e.getEmpno().equals(empno)) return e;
         }
         return null;
   }
  
   public Emp createEmp(Emp e) {
         emps.add(e);
         return e;
   }
  
   public Long deleteEmp(Long empno) {
         for(Emp e : emps)  {
               if (e.getEmpno().equals(empno)) {
                     emps.remove(e);
                     return empno;
               }
         }
         return null;
   }
  
   public Emp updateEmp(Long empno, Emp e) {
         for (Emp emp : emps) {
               if (emp.getEmpno().equals(empno)) {
                     e.setEmpno(emp.getEmpno());
                     emps.remove(emp);
                     emps.add(e);
                     return e;
               }
         }

         return null;
   }
}

n  [EmpController.java]
package com.example.demo;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class EmpController {
  
   @Autowired
   private EmpDAO empDAO;
  
   @GetMapping("/emp/all")
    public List<Emp> getEmps() {
         System.out.println();
        return empDAO.getEmps();
    }
  
   @GetMapping("/emp/{empno}")
    public ResponseEntity<Emp> getEmp(@PathVariable("empno") Long empno) {
         Emp e = empDAO.getEmp(empno);
         if (e == null) {
               return new ResponseEntity<Emp>(HttpStatus.NOT_FOUND);
         }
        return new ResponseEntity<Emp>(e, HttpStatus.OK);
    }
  
   @PostMapping(value="/emp/create")
   public ResponseEntity<Emp> createEmp(@RequestBody Emp e) {
         empDAO.createEmp(e);
         return new ResponseEntity<Emp>(e, HttpStatus.OK);
   }
  
   @DeleteMapping("/emp/delete/{empno}")
   public ResponseEntity<Long> deleteEmp(@PathVariable Long empno) {
         if (null == empDAO.deleteEmp(empno)) {
               return new ResponseEntity<Long>(HttpStatus.NOT_FOUND);
         }
         return new ResponseEntity<Long>(empno, HttpStatus.OK);
   }    
  
   @PutMapping("/emp/update/{empno}")
   public ResponseEntity<Emp> updateCustomer(@PathVariable Long empno@RequestBody Emp e) {

         e = empDAO.updateEmp(empnoe);

         if (null == ereturn new ResponseEntity<Emp>(HttpStatus.NOT_FOUND);

         return new ResponseEntity<Emp>(e, HttpStatus.OK);
   }
}

n  EmpApplication.java에서 마우스 우측버튼 >> Run As >> Java Application을 클릭 하여 실행 후 브라우저에서 확인하자.
n  [전체 사원 조회]
n  한명의 사원 조회

n  이제는 Xamarin.Forms 응용프로그램에서 모바일 UI를 만들어서 테스트해보자.
n  비주얼 스튜디오 2017 커뮤니티를 실행 후 Xamarin.Forms 크로스 플랫폼 앱, PCL 프로젝트를 생성하자.


n  다음화면에서 Xamarin.Forms, PCL 선택 후 OK 클릭.

전체 프로젝트 구조

n  Xamarin.Forms에서 인터넷 연결을 체크할 수 있는 “Xam.Plugin.Connectivity” Nuget 패키지를 설치하자솔루션에서 마우스 우측버튼 >> 솔루션용 NuGet 패키지 관리 >> 찾아보기 에서 “Xam.Plugin.Connectivity” 입력 후 설치.

n  Xamarin.Forms에서 HttpClient를 사용할 예정인데 직접 다룰 수 는 없으므로 “Microsoft.Net.Http” Nuget 패키지를 추가해야 한다. “Microsoft.Net.Http”를 포함시키기 위해 솔루션 >> 우측마우스 >> 솔루션용 NuGet 패키지 관리에서 Microsoft.Bcl.Build"를 추가한다.

n  솔루션 >> 우측마우스 >> 솔루션용 NuGet 패키지 관리에서 Microsoft.Net.Http"를 추가한다.

n  안드로이드 플랫폼에서 테스트를 위해 안드로이드쪽 프로젝트에서 Properties를 더블클릭 하여 “Android 매니페스트옵션” >> “필수권한에서 “ACCESS_NETWORK_STATE”, “INTERNET” 권한을 체크하자.

n  웹서비스 쪽에서 응답으로 넘어오는 JSON 형식의 문자열에 대응하는 C# 클래스(Emp.cs)를 Model 폴더에 만들자http://json2csharp.com/ 사이트에 JSON 문자열을 C# 클래스로 매핑하는 솔루션이 있어 이를 사용하기로 한다.
n  [Emp.cs]  <<= 이식가능 프로젝트에 Model를 만들고 그 안에 위치
using System.Collections.Generic;

namespace Emp.Model
{
    public  class Emp
    {
        public int Empno { getset; }
        public string Ename { getset; }
        public int Sal { getset; }
        public string Job { getset; }
    }

    public class EmpList
    {
        public List<Emp> emps { getset; }
    }
}

n  자마린 프로젝트에 Newtonsoft.Json” Nuget 패키지를 추가해야 한다이전에 추가한 방식대로 설치하자.

n  마찬가지로 이식 가능 프로젝트에 View 폴더를 만들고 전체 사원 목록을 출력하기 위한 MainPage.xaml 파일을 만들자. (기존에 있는 MainPage.xaml 파일을 위치 이동 시키자.)
n  [MainPage.xaml]
<?xml version="1.0" encoding="utf-8" ?>
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:Emp"
             x:Class="Emp.MainPage">
    <Grid>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Button x:Name="Button1" Grid.Row="0" Margin="10" Text="사원 리스트 보기" Clicked="Button1_Click" />           
            <ListView x:Name="listView" Grid.Row="1" HorizontalOptions="FillAndExpand"
                      HasUnevenRows="True" ItemSelected="listView_ItemSelected">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <Grid HorizontalOptions="FillAndExpand" Padding="10">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition Height="Auto"/>
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="1*"/>
                                    <ColumnDefinition Width="1*"/>
                                </Grid.ColumnDefinitions>
                                <Label Text="{Binding Empno}" Grid.Row="0" Grid.Column="0" TextColor="Red" HorizontalTextAlignment="Center"/>
                                <Label Text="{Binding Ename}" Grid.Row="0" Grid.Column="1" TextColor="Blue"  HorizontalTextAlignment="Center"/>
                               
                                <BoxView HeightRequest="1" Margin="0,5,5,0" BackgroundColor="Gray" Grid.Row="2" Grid.ColumnSpan="2" HorizontalOptions="FillAndExpand" />
                            </Grid>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </Grid>
        <ActivityIndicator x:Name="activityIndicator" IsRunning="True" IsVisible="false" Color="Green"/>
    </Grid>
</ContentPage>
n  [MainPage.xaml.cs]
using Newtonsoft.Json;
using Plugin.Connectivity;
using System.Collections.Generic;
using System.Net.Http;
using Xamarin.Forms;

namespace Emp
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();           
        }

        //사원 전체 목록 출력
        private async void Button1_Click(object sender, System.EventArgs e)
        {
            /* 응답 JSON 형식
        * [{"empno":1001,"ename":"TopCredu","sal":6000,"job":"CLERK"},
        * {"empno":1002,"ename":"Jhon Denver","sal":7000,"job":"SALESMAN"},
        * {"empno":1003,"ename":"Karl Luice","sal":8000,"job":"MANAGER"},
        * {"empno":1004,"ename":"Chanho Park","sal":7000,"job":"SALESMAN"},
        * {"empno":1005,"ename":"Phile Migalon","sal":8000,"job":"MANAGER"},
        * {"empno":1006,"ename":"Jhon Smith","sal":7500,"job":"SALESMAN"},
        * {"empno":1007,"ename":"OracleJavaCommunity","sal":6800,"job":"CLERK"},
        * {"empno":1008,"ename":"Ojc.Asia","sal":7200,"job":"CLERK"}]
        * */

            activityIndicator.IsVisible = true;
            string url = "http://192.168.0.189:8080/emp/all";

            // 네트워크 연결 상태 확인
            if (CrossConnectivity.Current.IsConnected)
            {

                var client = new HttpClient();
                var res = await client.GetAsync(url);
                string ResponseStr = await res.Content.ReadAsStringAsync();

                //EmpList empList = new EmpList();

                if (ResponseStr != "")
                {
                    // 웹서비스에서 리턴하는 JSON 형식을 EmpList 형식으로 변환
                    listView.ItemsSource = JsonConvert.DeserializeObject<List<Model.Emp>>(ResponseStr);
                }
                // 리스트뷰의 아이템소스로 emps 컬렉션을 할당 화면에 출력됨
                // listView.ItemsSource = empList.Emps;
            }
            else
            {
                await DisplayAlert("에러!""네트워크 연결상태를 확인하세요.""Ok");
            }
            //응답이 다 넘어온 경우 비활성화 시킴
            activityIndicator.IsVisible = false;
        }

        //선택한 사원을 다음 화면에 출력
        private async void listView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
        {
/* 응답 JSON 형식
{"empno":1001,"ename":"TopCredu","sal":6000,"job":"CLERK"}
*/
            activityIndicator.IsVisible = true;

            var Emp = e.SelectedItem as Model.Emp;
            var nextPage = new View.EmpViewPage();
           

            //웹서비스 호출 URL 생성
            string url = "http://192.168.0.189:8080/emp/" + Emp.Empno;

            // 네트워크 연결 상태 확인
            if (CrossConnectivity.Current.IsConnected)
            {

                var client = new HttpClient();
                var res = await client.GetAsync(url);
                string ResponseStr = await res.Content.ReadAsStringAsync();

                if (ResponseStr != "")
                {
                    // 웹서비스에서 리턴하는 JSON 형식을 EmpList 형식으로 변환
                    nextPage.BindingContext = JsonConvert.DeserializeObject<Model.Emp>(ResponseStr);
                }
            }
            else
            {
                await DisplayAlert("에러!""네트워크 연결상태를 확인하세요.""Ok");
            }
            //응답이 다 넘어온 경우 비활성화 시킴
            activityIndicator.IsVisible = false;

            await Navigation.PushAsync(nextPage);

        }
    }
}

n  사원 데이터를 보기 위한 상세 페이지 UI를 작성 하자. (새 창에서 실행됨)
n  View 폴더 아래에서 추가 >> 새항목추가 >> Xamarin.Forms >> Content Page 템플릿으로 EmpViewPage.xaml 을 추가하자.

n  EmpViewPage는 전체 사원 목록 보기(ListView)에서 한 사원을 선택했을 때 새로 뜨는 창이며 보통 ListView의 있는 내용을 가지고 뜨지만 본 예제에서는 자바스프링쪽의 웹서비를 호출 하면서 사번을 넘겨주고 응답으로 해당 사원객체를 JSON 형식으로 받아서 데이터 바인딩을 이용하여 화면에 출력했다.
n  [EmpViewPage.xaml]
<?xml version="1.0" encoding="utf-8" ?>
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Emp.View.EmpViewPage">
    <StackLayout>

        <Label Text="사원 상세보기" HorizontalOptions="Center" TextColor="Blue" FontSize="30"/>
        <Grid x:Name="GridDetails" VerticalOptions="Center" HorizontalOptions="Center" Margin="0, 10, 10, 0" >
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="1*"/>
            </Grid.ColumnDefinitions>

            <Label Text="사번:" Grid.Row="0" Grid.Column="0" HorizontalOptions="Center" FontAttributes="Bold"/>
            <Label Text="{Binding Empno}" Grid.Row="0" Grid.Column="1" HorizontalOptions="Center" />
            <BoxView HeightRequest="2" Margin="10,10,10,0" BackgroundColor="Gray" Grid.Row="1" Grid.ColumnSpan="2" />

            <Label Text="이름:" Grid.Row="2" Grid.Column="0" HorizontalOptions="Center" FontAttributes="Bold"/>
            <Label Text="{Binding Ename}" Grid.Row="2" Grid.Column="1" HorizontalOptions="Center" />
            <BoxView HeightRequest="2" Margin="10,10,10,0" BackgroundColor="Gray" Grid.Row="3" Grid.ColumnSpan="2" />

            <Label Text="급여($):" Grid.Row="4" Grid.Column="0" HorizontalOptions="Center" FontAttributes="Bold"/>
            <Label Text="{Binding Sal}" Grid.Row="4" Grid.Column="1" HorizontalOptions="Center"/>
            <BoxView HeightRequest="2" Margin="10,10,10,0" BackgroundColor="Gray" Grid.Row="5" Grid.ColumnSpan="2" />

            <Label Text="직무:" Grid.Row="6" Grid.Column="0" HorizontalOptions="Center" FontAttributes="Bold"/>
            <Label Text="{Binding Job}" Grid.Row="6" Grid.Column="1" HorizontalOptions="Center" />
            <BoxView HeightRequest="2" Margin="10,10,10,0" BackgroundColor="Gray" Grid.Row="7" Grid.ColumnSpan="2" />
        </Grid>
    </StackLayout>
</ContentPage>
n  [EmpViewPage.xaml.cs] 파일은 수정할 필요없다.
n  에뮬레이터는 그냥 실행하면 되지만 안드로이드 휴대폰에서 실습을 위해서는 모바일에서 웹서비스에 접근 가능 해야 하므로 PC의 네트워크와 같은 네트워크의 Wifi에 휴대폰을 연결하고 테스트 하면 된다


댓글 없음:

댓글 쓰기