diff --git a/src/main/java/HWLesson_8/AppGlobalState.java b/src/main/java/HWLesson_8/AppGlobalState.java new file mode 100644 index 0000000..559ca66 --- /dev/null +++ b/src/main/java/HWLesson_8/AppGlobalState.java @@ -0,0 +1,96 @@ +package HWLesson_8; + +import java.sql.*; + +public class AppGlobalState { + + static { + try { + Class.forName("org.sqlite.JDBC"); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + + private static Connection connection; + + private static Statement statement; + + private static PreparedStatement insertWeatherPreparedStatement; + + private static AppGlobalState instance; + + public String cityName1; + + private String cityKey; + + public String getCityName1() { + + return cityName1; + } + + public static Connection getConnection() { + + return connection; + } + + public static Statement getStatement(){ + return statement; + } + + public static PreparedStatement getInsertWeatherPreparedStatement() { + + return insertWeatherPreparedStatement; + } + + public void setCityName1(String cityName1) { + + this.cityName1 = cityName1; + } + + public String getCityKey() { + + return cityKey; + } + + public void setCityKey(String cityKey) { + + this.cityKey = cityKey; + } + + public String getDbName() { + + return "weather-app.db"; + } + + + private AppGlobalState() { + try { + connection = DriverManager.getConnection("jdbc:sqlite:c:\\sqlite\\"+getDbName()); + statement = connection.createStatement(); + statement.executeUpdate("CREATE TABLE IF NOT EXISTS weather(" + + "date TEXT NOT NULL,city TEXT NOT NULL, temp TEXT NOT NULL, text TEXT NOT NULL);"); + insertWeatherPreparedStatement = connection.prepareStatement( + "INSERT INTO weather (date, city, temp, text) VALUES (?,?,?,?);" + ); + + + + } catch (SQLException throwable) { + throwable.printStackTrace(); + System.exit(1); + } + } + public static AppGlobalState getInstance () { + if (instance == null) { + instance = new AppGlobalState(); + } + return instance; + } + + + public String getApiKey() { + + return "fx9gkDPNYPPSGK87ixzUPZKVsbl01DQR"; + } +} \ No newline at end of file diff --git a/src/main/java/HWLesson_8/UserCommands.java b/src/main/java/HWLesson_8/UserCommands.java new file mode 100644 index 0000000..e9fb4a0 --- /dev/null +++ b/src/main/java/HWLesson_8/UserCommands.java @@ -0,0 +1,6 @@ +package HWLesson_8; + +public enum UserCommands { + GET_CURRENT_WEATHER, + GET_NEXT_FIVE_DAYS_WEATHER +} diff --git a/src/main/java/HWLesson_8/WeatherApp.java b/src/main/java/HWLesson_8/WeatherApp.java new file mode 100644 index 0000000..7e4409e --- /dev/null +++ b/src/main/java/HWLesson_8/WeatherApp.java @@ -0,0 +1,15 @@ +package HWLesson_8; + +import HWLesson_8.view.IUserInterface; +import HWLesson_8.view.UserInterface; + +public class WeatherApp { + public static void main(String[] args) { + + IUserInterface ui = new UserInterface(); + + ui.showMenu(); + + + } +} diff --git a/src/main/java/HWLesson_8/controller/Controller.java b/src/main/java/HWLesson_8/controller/Controller.java new file mode 100644 index 0000000..ce82a11 --- /dev/null +++ b/src/main/java/HWLesson_8/controller/Controller.java @@ -0,0 +1,53 @@ +package HWLesson_8.controller; + +import HWLesson_8.*; +import HWLesson_8.model.*; + +import java.io.IOException; +import java.text.ParseException; +import java.util.List; + +public class Controller implements IController { + + ICityCodeProvider codeProvider = new AccuWeatherCityCodeProvider(); + IWeatherProvider weatherProvider = new AccuWeatherProvider(); + IWeatherRepository weatherRepository = new SQLiteWeatherRepository(); + + + @Override + public void onCityInput(String city) throws IOException { + + if(city.length() == 1) { + throw new IOException("Недопустимо короткое название города"); + } + codeProvider.getCodeByCityName(city); + + } + + @Override + public void onCommandChosen(int selectedCommand) throws IOException, ParseException { + System.out.println(" "); + switch (selectedCommand) { + case 1: { + Weather currentWeather = weatherProvider.getCurrentWeather(AppGlobalState.getInstance().getCityKey()); + System.out.println(currentWeather); + weatherRepository.saveWeatherObject(currentWeather); + break; + } + case 2: { + weatherProvider.getWeatherForFiveDays(AppGlobalState.getInstance().getCityKey()); + break; + } + case 3: { + List allData = weatherRepository.getAllData(); + allData.forEach(System.out::println); + + break; + } + default: { + throw new IOException("Вы ввели данные неверно.\n"); + } + } + } + +} \ No newline at end of file diff --git a/src/main/java/HWLesson_8/controller/IController.java b/src/main/java/HWLesson_8/controller/IController.java new file mode 100644 index 0000000..2cecdbd --- /dev/null +++ b/src/main/java/HWLesson_8/controller/IController.java @@ -0,0 +1,11 @@ +package HWLesson_8.controller; + +import java.io.IOException; +import java.text.ParseException; + +public interface IController { + + void onCityInput(String city) throws IOException; + + void onCommandChosen(int selectedCommand) throws IOException, ParseException; +} diff --git a/src/main/java/HWLesson_8/model/AccuWeatherCityCodeProvider.java b/src/main/java/HWLesson_8/model/AccuWeatherCityCodeProvider.java new file mode 100644 index 0000000..7734e06 --- /dev/null +++ b/src/main/java/HWLesson_8/model/AccuWeatherCityCodeProvider.java @@ -0,0 +1,72 @@ +package HWLesson_8.model; + +import HWLesson_8.AppGlobalState; +import com.fasterxml.jackson.databind.ObjectMapper; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +import java.io.IOException; + +public class AccuWeatherCityCodeProvider implements ICityCodeProvider { + + private static final String BASE_HOST = "dataservice.accuweather.com"; + private static final String LOCATIONS_SERVICE_PATH = "locations"; + private static final String API_VERSION = "v1"; + private static final String API_KEY = AppGlobalState.getInstance().getApiKey(); + + + private final OkHttpClient client = new OkHttpClient(); + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public void getCodeByCityName(String cityName) throws IOException { + //http://dataservice.accuweather.com/locations/v1/cities/autocomplete?apikey={{accuweatherApiKey}}&q=Brest + + HttpUrl detectLocationUrl = new HttpUrl.Builder() + .scheme("http") + .host(BASE_HOST) + .addPathSegment(LOCATIONS_SERVICE_PATH) + .addPathSegment(API_VERSION) + .addPathSegment("cities") + .addPathSegment("autocomplete") + .addQueryParameter("apikey", API_KEY) + .addQueryParameter("q", cityName) + .build(); + + Request detectLocationRequest = new Request.Builder() + .addHeader("accept", "application/json") + .url(detectLocationUrl) + .build(); + + + Response response = client.newCall(detectLocationRequest).execute(); + if (!response.isSuccessful()) { + throw new IOException("Сетевая ошибка\n"); + } + + assert response.body() != null; + String jsonBody = response.body().string(); + + if (objectMapper.readTree(jsonBody).size() < 1) { + throw new IOException("Города с таким названием не нашлось\n"); + } + + String cityTitle = objectMapper.readTree(jsonBody).get(0).at("/LocalizedName").asText(); + String countryTitle = objectMapper.readTree(jsonBody).get(0).at("/Country/LocalizedName").asText(); + + String cityKey = objectMapper.readTree(jsonBody).get(0).at("/Key").asText(); + System.out.println("* * * * * * * * * *"); + + System.out.printf("Поиск завершен. Город %s в стране %s!\n", cityTitle, countryTitle); + System.out.println("* * * * * * * * * *"); + AppGlobalState.getInstance().setCityName1(cityTitle); + + + AppGlobalState.getInstance().setCityKey(cityKey); + + } + + +} \ No newline at end of file diff --git a/src/main/java/HWLesson_8/model/AccuWeatherProvider.java b/src/main/java/HWLesson_8/model/AccuWeatherProvider.java new file mode 100644 index 0000000..67bb8a5 --- /dev/null +++ b/src/main/java/HWLesson_8/model/AccuWeatherProvider.java @@ -0,0 +1,122 @@ +package HWLesson_8.model; + +import HWLesson_8.AppGlobalState; +import com.fasterxml.jackson.databind.ObjectMapper; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class AccuWeatherProvider implements IWeatherProvider { + + private static final String BASE_HOST = "dataservice.accuweather.com"; + private static final String CONDITIONS_PATH = "currentconditions"; + private static final String FORECASTS = "forecasts"; + private static final String API_VERSION = "v1"; + private static final String DAILY = "daily"; + private static final String DAYS = "5day"; + private static final String API_KEY = AppGlobalState.getInstance().getApiKey(); + + private final OkHttpClient client = new OkHttpClient(); + private final ObjectMapper objectMapper = new ObjectMapper(); + + + @Override + public Weather getCurrentWeather(String cityKey) throws IOException, ParseException { + //http://dataservice.accuweather.com/currentconditions/v1/27497?apikey={{accuweatherApiKey}} + + HttpUrl getWeatherUrl = new HttpUrl.Builder() + .scheme("http") + .host(BASE_HOST) + .addPathSegment(CONDITIONS_PATH) + .addPathSegment(API_VERSION) + .addPathSegment(cityKey) + .addQueryParameter("apikey", API_KEY) + .build(); + Request getWeatherRequest = new Request.Builder() + .addHeader("accept", "application/json") + .url(getWeatherUrl) + .build(); + + Response response = client.newCall(getWeatherRequest).execute(); + if (!response.isSuccessful()) { + throw new IOException("Ошибка сети\n"); + } + + assert response.body() != null; + String jsonBody2 = response.body().string(); + + String OneDayCityName = AppGlobalState.getInstance().getCityName1(); + String OneDay = objectMapper.readTree(jsonBody2).get(0).at("/LocalObservationDateTime").asText().substring(0,10); + + SimpleDateFormat oldDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + SimpleDateFormat newDateFormat = new SimpleDateFormat("dd.MM.yyyy"); + Date date = oldDateFormat.parse(OneDay); + String OneDayForecastDate = newDateFormat.format(date); + + String OneDayDescription = objectMapper.readTree(jsonBody2).get(0).at("/WeatherText").asText().toLowerCase(); + String OneDayTemperature = objectMapper.readTree(jsonBody2).get(0).at("/Temperature/Metric/Value").asText(); + + + Weather weather = new Weather(OneDayForecastDate, OneDayCityName, OneDayTemperature, OneDayDescription); + return weather; + } + + @Override + public void getWeatherForFiveDays(String cityKey) throws IOException, ParseException { +//http://dataservice.accuweather.com/forecasts/v1/daily/5day/295212?apikey=XYHQlFgxfVgXHA2ydmRCbLLAQacY1QbQ&language=ru&metric=true + + HttpUrl getWeatherUrl = new HttpUrl.Builder() + .scheme("http") + .host(BASE_HOST) + .addPathSegment(FORECASTS) + .addPathSegment(API_VERSION) + .addPathSegment(DAILY) + .addPathSegment(DAYS) + .addPathSegment(cityKey) + .addQueryParameter("apikey", API_KEY) + .addQueryParameter("metric","true") + .build(); + + Request getWeatherRequest = new Request.Builder() + .addHeader("accept", "application/json") + .url(getWeatherUrl) + .build(); + + Response response = client.newCall(getWeatherRequest).execute(); + if (!response.isSuccessful()) { + throw new IOException("Ошибка сети\n"); + } + assert response.body() != null; + String jsonBody2 = response.body().string(); + + System.out.println(" "); + + for (int i = 0; i < 5; i++) { + + String firstDay = objectMapper.readTree(jsonBody2).at("/DailyForecasts/"+i+"/Date").asText().substring(0,10); + SimpleDateFormat oldDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + SimpleDateFormat newDateFormat = new SimpleDateFormat("dd.MM.yyyy"); + Date date = oldDateFormat.parse(firstDay); + String dayForecastDate = newDateFormat.format(date); + + String dayCityName = AppGlobalState.getInstance().getCityName1(); + + String dayTemperatureMin = objectMapper.readTree(jsonBody2).at("/DailyForecasts/"+i+"/Temperature/Minimum/Value").asText(); + String dayTemperatureMax = objectMapper.readTree(jsonBody2).at("/DailyForecasts/"+i+"/Temperature/Maximum/Value").asText(); + + String dayDescriptionDay = objectMapper.readTree(jsonBody2).at("/DailyForecasts/"+i+"/Day/IconPhrase").asText().toLowerCase(); + String dayDescriptionNight = objectMapper.readTree(jsonBody2).at("/DailyForecasts/"+i+"/Night/IconPhrase").asText().toLowerCase(); + + System.out.println("* * * * * * * * * *"); + System.out.printf("На дату %s в городе %s погода днем %s, погода ночью %s, а температура от %sC до %sC\n", dayForecastDate, dayCityName, dayDescriptionDay,dayDescriptionNight, dayTemperatureMin, dayTemperatureMax); + + } + + } + +} diff --git a/src/main/java/HWLesson_8/model/ICityCodeProvider.java b/src/main/java/HWLesson_8/model/ICityCodeProvider.java new file mode 100644 index 0000000..19f4c48 --- /dev/null +++ b/src/main/java/HWLesson_8/model/ICityCodeProvider.java @@ -0,0 +1,7 @@ +package HWLesson_8.model; + +import java.io.IOException; + +public interface ICityCodeProvider { + void getCodeByCityName(String cityName) throws IOException; +} diff --git a/src/main/java/HWLesson_8/model/IWeatherProvider.java b/src/main/java/HWLesson_8/model/IWeatherProvider.java new file mode 100644 index 0000000..13d3570 --- /dev/null +++ b/src/main/java/HWLesson_8/model/IWeatherProvider.java @@ -0,0 +1,12 @@ +package HWLesson_8.model; + +import java.io.IOException; +import java.text.ParseException; + +public interface IWeatherProvider { + + Weather getCurrentWeather(String cityKey) throws IOException, ParseException; + + void getWeatherForFiveDays(String cityKey) throws IOException, ParseException; + +} diff --git a/src/main/java/HWLesson_8/model/IWeatherRepository.java b/src/main/java/HWLesson_8/model/IWeatherRepository.java new file mode 100644 index 0000000..75556cd --- /dev/null +++ b/src/main/java/HWLesson_8/model/IWeatherRepository.java @@ -0,0 +1,10 @@ +package HWLesson_8.model; + +import java.util.List; + +public interface IWeatherRepository { + + List getAllData(); + + void saveWeatherObject (Weather weather); +} diff --git a/src/main/java/HWLesson_8/model/SQLiteWeatherRepository.java b/src/main/java/HWLesson_8/model/SQLiteWeatherRepository.java new file mode 100644 index 0000000..d95351a --- /dev/null +++ b/src/main/java/HWLesson_8/model/SQLiteWeatherRepository.java @@ -0,0 +1,48 @@ +package HWLesson_8.model; + +import HWLesson_8.AppGlobalState; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; + +public class SQLiteWeatherRepository implements IWeatherRepository { + @Override + public List getAllData() { + Statement statement = AppGlobalState.getStatement(); + List result = new ArrayList<>(); + + try { + ResultSet rs = statement.executeQuery("SELECT * FROM weather"); + while (rs.next()){ + result.add(new Weather( + rs.getString(1), + rs.getString(2), + rs.getString(3), + rs.getString(4) + )); + } + } catch (SQLException throwable) { + throwable.printStackTrace(); + } + + return result; + } + + @Override + public void saveWeatherObject(Weather weather) { + PreparedStatement insertOne = AppGlobalState.getInsertWeatherPreparedStatement(); + try { + insertOne.setString(1, Weather.getDate()); + insertOne.setString(2, Weather.getCity()); + insertOne.setString(3, Weather.getTemperature()); + insertOne.setString(4, Weather.getWeatherText()); + insertOne.executeUpdate(); + } catch (SQLException throwable) { + throwable.printStackTrace(); + } + } +} diff --git a/src/main/java/HWLesson_8/model/Weather.java b/src/main/java/HWLesson_8/model/Weather.java new file mode 100644 index 0000000..47614ee --- /dev/null +++ b/src/main/java/HWLesson_8/model/Weather.java @@ -0,0 +1,58 @@ +package HWLesson_8.model; + +public class Weather { + + private static String date; + private static String city; + private static String temperature; + private static String weatherText; + + public Weather(String date, String city, String temperature, String weatherText) { + Weather.date = date; + Weather.city = city; + Weather.temperature = temperature; + Weather.weatherText = weatherText; + } + + public Weather() { + } + + public static String getDate() { + return date; + } + + public void setDate(String date) { + Weather.date = date; + } + + public static String getCity() { + return city; + } + + public void setCity(String city) { + Weather.city = city; + } + + public static String getTemperature() { + return temperature; + } + + public void setTemperature(String temperature) { + Weather.temperature = temperature; + } + + public static String getWeatherText() { + return weatherText; + } + + public void setWeatherText(String weatherText) { + Weather.weatherText = weatherText; + } + + @Override + public String toString() { + return "\nНа дату "+ date + " в городе " + city + " ожидается погода " + weatherText + " с температурой окружающего воздуха " +temperature+" градусов Цельсия."; + } + + +} \ No newline at end of file diff --git a/src/main/java/HWLesson_8/view/IUserInterface.java b/src/main/java/HWLesson_8/view/IUserInterface.java new file mode 100644 index 0000000..013f29b --- /dev/null +++ b/src/main/java/HWLesson_8/view/IUserInterface.java @@ -0,0 +1,5 @@ +package HWLesson_8.view; + +public interface IUserInterface { + void showMenu (); +} diff --git a/src/main/java/HWLesson_8/view/UserInterface.java b/src/main/java/HWLesson_8/view/UserInterface.java new file mode 100644 index 0000000..0e0a414 --- /dev/null +++ b/src/main/java/HWLesson_8/view/UserInterface.java @@ -0,0 +1,67 @@ +package HWLesson_8.view; + +import HWLesson_8.controller.Controller; +import HWLesson_8.controller.IController; + +import java.io.IOException; +import java.text.ParseException; +import java.util.Scanner; + +public class UserInterface implements IUserInterface { + + IController controller = new Controller(); + @Override + public void showMenu() { + while (true) { + System.out.println("\nПрограмма начала работу."); + System.out.println("Введите 1 или 2 для получения желаемых данных:"); + System.out.println("\n1 - хочу знать о погоде в каком-то городе\n2 - хочу получить информацию из предыдущих обращений к программе\n \nвведите 'exit' для выхода"); + + Scanner scanner = new Scanner(System.in); + + String menuChoice = scanner.nextLine(); + + checkIsExit(menuChoice); + + + if (menuChoice.equalsIgnoreCase("2")) { + try { + controller.onCommandChosen(3); + } catch (IOException | ParseException e) { + e.printStackTrace(); + } + } else { + System.out.println("Введите имя города на латинице:"); + String userResponse = scanner.nextLine(); + + try { + controller.onCityInput(userResponse); + } catch (Exception e) { + e.printStackTrace(); + continue; + } + + System.out.println("Введите команду\n1 - для получения погоды на текущий день\n2 - для получения погоды на 5 дней"); + + + System.out.println("* * * * * * * * * *"); + int selectedCommand = scanner.nextInt(); + + try { + controller.onCommandChosen(selectedCommand); + } catch (IOException | ParseException e) { + e.printStackTrace(); + } + } + } + } + + private void checkIsExit(String userResponse) { + if (userResponse.equalsIgnoreCase("exit") || + userResponse.equalsIgnoreCase("выход")) { + + System.out.println("Программа завершает работу. Хорошего дня!"); + System.exit(0); + } + } +} \ No newline at end of file