부산 연극 정보 앱
해당 프로젝트 깃허브 주소
https://github.com/OHYUNBEOM/WPF
https://github.com/OHYUNBEOM/WPF/tree/main/OpenAPIProject/wpf_OpenAPI기술 스택
MahApps
OpenAPI
MySQL
1) 공공 데이터 포털 API 신청
https://www.data.go.kr/iim/api/selectAPIAcountView.do
부산 연극 정보 API
2) 누겟 패키지 설치
- MahApps.Metro
- MahApps.Metro.Icon
- Newtonsoft.Json
- MySql.Data
3) MySQL 테이블 생성
MySql 초기 상태
App.xaml
<Application x:Class="wpf_OpenAPI.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:wpf_OpenAPI" StartupUri="MainWindow.xaml"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! --> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" /> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" /> <!-- Theme setting --> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Crimson.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> </Application>
MainWindow.xaml
<mah:MetroWindow x:Class="wpf_OpenAPI.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls" xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks" xmlns:local="clr-namespace:wpf_OpenAPI" mc:Ignorable="d" Title="부산 연극 정보" Height="600" Width="1600" FontFamily="NanumGothic"> <mah:MetroWindow.IconTemplate> <DataTemplate> <iconPacks:PackIconPixelartIcons Kind="Movie" Foreground="White" Margin="5,7,0,0"/> </DataTemplate> </mah:MetroWindow.IconTemplate> <Grid> <Grid.RowDefinitions> <RowDefinition Height="80"/> <RowDefinition Height="1*"/> <RowDefinition Height="25"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="1*"/> <ColumnDefinition Width="1*"/> </Grid.ColumnDefinitions> <Grid Grid.Row="0" Grid.Column="0"> <Label Content="Busan Play Information" FontSize="30" FontWeight="Bold" Margin="10" HorizontalAlignment="Center" FontStyle="Italic"/> </Grid> <StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Center"> <Button x:Name="BtnPlaySearch" Content="부산 연극 조회" Margin="5" Style="{StaticResource MahApps.Styles.Button.Dialogs.Accent}" Width="130" Click="BtnPlaySearch_Click"/> <Button x:Name="BtnPlayInsertDB" Content="저장" Margin="5" Style="{StaticResource MahApps.Styles.Button.Dialogs.Accent}" Width="80" Click="BtnPlayInsertDB_Click"/> <TextBox Width="230" x:Name="TxtPlayName" FontSize="15" Margin="5,10,5,20" mah:TextBoxHelper.Watermark="검색할 연극명 입력" mah:TextBoxHelper.UseFloatingWatermark="True" mah:TextBoxHelper.ClearTextButton="True" InputMethod.PreferredImeState="On" InputMethod.PreferredImeConversionMode="Native" KeyDown="TxtPlayName_KeyDown"/> <Button x:Name="BtnSearchPlay" Content="검색" Margin="5" Style="{StaticResource MahApps.Styles.Button.Dialogs.Accent}" Width="60" Click="BtnSearchPlay_Click"/> </StackPanel> <!--데이터 그리드--> <DataGrid Grid.Row="1" Grid.ColumnSpan="2" x:Name="GrdResult" Style="{StaticResource MahApps.Styles.DataGrid.Azure}" Margin="10,10,10,10" IsReadOnly="True" ItemsSource="{Binding}" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Binding="{Binding Title}" Header="제목" FontWeight="Bold" Width="590"/> <DataGridTextColumn Binding="{Binding Place_nm}" Header="시설명" FontWeight="Bold" Width="370"/> <DataGridTextColumn Binding="{Binding Op_st_dt}" Header="공연시작일" FontWeight="Bold" Width="160"/> <DataGridTextColumn Binding="{Binding Op_ed_dt}" Header="공연종료일" FontWeight="Bold" Width="160"/> <DataGridTextColumn Binding="{Binding Pay_at}" Header="유무료 구분" FontWeight="Bold" Width="80"/> <DataGridTextColumn Binding="{Binding Op_at}" Header="오픈런" FontWeight="Bold" Width="60"/> <DataGridTextColumn Binding="{Binding Res_no}" Header="공연번호" FontWeight="Bold" Width="100"/> </DataGrid.Columns> </DataGrid> <!--상태 바--> <StatusBar Grid.Row="2" Grid.ColumnSpan="2" Grid.RowSpan="2" Margin="0,0,0,0"> <StatusBarItem Content="부산 연극 정보 조회 앱 "/> <Separator Style="{StaticResource MahApps.Styles.Separator.StatusBar}"/> <StatusBarItem x:Name="StsResult"/> </StatusBar> </Grid> </mah:MetroWindow>
Mainwindow.xaml.cs
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using MahApps.Metro.Controls; using MySql.Data.MySqlClient; using Newtonsoft.Json.Linq; using wpf_OpenAPI.Logics; using wpf_OpenAPI.Models; using wpf_OpenAPI.Logics; using wpf_OpenAPI.Models; using System.Diagnostics; using System.Data; namespace wpf_OpenAPI { /// <summary> /// MainWindow.xaml에 대한 상호 작용 논리 /// </summary> public partial class MainWindow : MetroWindow { public MainWindow() { InitializeComponent(); } // 부산 연극 정보 API 조회 private async void BtnPlaySearch_Click(object sender, RoutedEventArgs e) { string key = "te5%2FahqxnGW00Gw1jJ92lJYLwkOvVrP9DZdSdffoIyZB8Jb%2BzHMrpMxU0VQOlxdvK%2BRzzcNsLTr%2BLaoLfFzUQg%3D%3D"; string openApiUri = $"https://apis.data.go.kr/6260000/BusanCulturePlayService/getBusanCulturePlay?serviceKey={key}&numOfRows=734&resultType=json"; string result = string.Empty; //WebRequest,WebResponse WebRequest req = null; WebResponse res = null; StreamReader reader = null; try { req = WebRequest.Create(openApiUri); res = await req.GetResponseAsync(); reader = new StreamReader(res.GetResponseStream()); result = reader.ReadToEnd(); } catch (Exception ex) { await Commons.ShowMessageAsync("오류", $"OpenAPI 조회오류 {ex.Message}"); } var jsonResult = JObject.Parse(result); var status = Convert.ToInt32(jsonResult["code"]); try { if(status==00) { var data = jsonResult["getBusanCulturePlay"]["item"]; var json_array = data as JArray; var playinfors = new List<PlayInfor>(); foreach (var infor in json_array) { playinfors.Add(new PlayInfor { Id=0, Res_no = Convert.ToInt32(infor["res_no"]), Title = Convert.ToString(infor["title"]), Op_st_dt = Convert.ToDateTime(infor["op_st_dt"]), Op_ed_dt = Convert.ToDateTime(infor["op_ed_dt"]), Op_at = Convert.ToString(infor["op_at"]), Place_nm = Convert.ToString(infor["place_nm"]), Pay_at = Convert.ToString(infor["pay_at"]) }); } this.DataContext= playinfors; StsResult.Content = $"부산 연극 정보 {playinfors.Count}건 조회 완료"; } } catch (Exception ex) { await Commons.ShowMessageAsync("오류", $"JSON 처리오류 {ex.Message}"); } } //조회된 연극정보 DB(MySQL)에 저장 private async void BtnPlayInsertDB_Click(object sender, RoutedEventArgs e) { if (GrdResult.Items.Count == 0) { await (Commons.ShowMessageAsync("오류", "연극 정보 조회 이후 저장하세요!")); return; } //DB에 저장 try { using (MySqlConnection conn = new MySqlConnection(Commons.myConnString)) { if (conn.State == System.Data.ConnectionState.Closed) conn.Open(); var query = @"INSERT INTO playinfor ( Res_no, Title, Op_st_dt, Op_ed_dt, Op_at, Place_nm, Pay_at) VALUES ( @Res_no, @Title, @Op_st_dt, @Op_ed_dt, @Op_at, @Place_nm, @Pay_at)"; var insRes = 0; foreach(var temp in GrdResult.Items) { if(temp is PlayInfor) { var item = temp as PlayInfor; MySqlCommand cmd = new MySqlCommand(query, conn); cmd.Parameters.AddWithValue("@Res_no", item.Res_no); cmd.Parameters.AddWithValue("@Title", item.Title); cmd.Parameters.AddWithValue("@Op_st_dt", item.Op_st_dt); cmd.Parameters.AddWithValue("@Op_ed_dt", item.Op_ed_dt); cmd.Parameters.AddWithValue("@Op_at", item.Op_at); cmd.Parameters.AddWithValue("@Place_nm", item.Place_nm); cmd.Parameters.AddWithValue("@Pay_at", item.Pay_at); insRes += cmd.ExecuteNonQuery(); } } await Commons.ShowMessageAsync("저장", "DB 저장 성공!"); StsResult.Content = $"DB 저장 {insRes}건 성공!"; } } catch (Exception ex) { await Commons.ShowMessageAsync("오류", $"DB저장 오류! {ex.Message}"); } } private void TxtPlayName_KeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Enter) { BtnSearchPlay_Click(sender, e); } } private async void BtnSearchPlay_Click(object sender, RoutedEventArgs e) { if(string.IsNullOrEmpty(TxtPlayName.Text)) { await Commons.ShowMessageAsync("검색", "검색할 연극명 입력하세요."); return; } this.DataContext = null; var Search_playinfors = new List<PlayInfor>(); //입력한 글자가 연극명에 포함된 연극 DB에서 찾아서 출력 try { using (MySqlConnection conn = new MySqlConnection(Commons.myConnString)) { if (conn.State == ConnectionState.Closed) conn.Open(); var query = $@"SELECT Id, Res_no, Title, Op_st_dt, Op_ed_dt, Op_at, Place_nm, Pay_at FROM playinfor WHERE Title LIKE '%{TxtPlayName.Text}%'"; var cmd = new MySqlCommand(query, conn); var adapter = new MySqlDataAdapter(cmd); var dSet = new DataSet(); adapter.Fill(dSet, "PlayInfor"); foreach(DataRow dr in dSet.Tables["PlayInfor"].Rows) { Search_playinfors.Add(new PlayInfor { Id = Convert.ToInt32(dr["Id"]), Res_no = Convert.ToInt32(dr["res_no"]), Title = Convert.ToString(dr["title"]), Op_st_dt = Convert.ToDateTime(dr["op_st_dt"]), Op_ed_dt = Convert.ToDateTime(dr["op_ed_dt"]), Op_at = Convert.ToString(dr["op_at"]), Place_nm = Convert.ToString(dr["place_nm"]), Pay_at = Convert.ToString(dr["pay_at"]) }); } this.DataContext = Search_playinfors; StsResult.Content = $"{TxtPlayName.Text} 가 포함된 연극명 {Search_playinfors.Count}건 조회 완료!"; } } catch (Exception ex) { await Commons.ShowMessageAsync("오류", $"오류 발생 : {ex.Message}"); } } } }
Logics/Commons.cs
using MahApps.Metro.Controls; using MahApps.Metro.Controls.Dialogs; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; namespace wpf_OpenAPI.Logics { public class Commons { //MySQL용 public static readonly string myConnString = "Server=localhost;" + "Port=3306;" + "Database=miniproject;" + "Uid=root;" + "Pwd=12345;"; // 비동기 메시지 창 public static async Task<MessageDialogResult> ShowMessageAsync(string title, string message, MessageDialogStyle style = MessageDialogStyle.Affirmative) { return await ((MetroWindow)Application.Current.MainWindow).ShowMessageAsync(title, message, style, null); } } }
Models/PlayInfor.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace wpf_OpenAPI.Models { public class PlayInfor { public int Id { get; set; } public int Res_no { get; set; } public string Title { get; set; } public DateTime Op_st_dt { get; set; } public DateTime Op_ed_dt { get; set; } public string Op_at { get; set; } public string Place_nm { get; set; } public string Pay_at { get; set; } } }
실행화면
1) Main 화면
2) 부산 연극 조회 버튼 Click
총 734건의 연극 정보를 뿌려줌3) 저장 버튼 --> DB에 연극 정보 저장
4) 연극명 입력 후 검색 버튼
DB에 저장된 TextBox의 글자가 포함된 연극 정보 추출