🙆

ITスクール DAY25 SimpleDateFormat/Calendar/HTTP/ネットワークI/O

2023/08/14に公開

初めに

今日は、例外処理、StringTokenizerクラスとSimpleDateFormat、I/O Streamの活用を中心に勉強しました。その中でもFormatクラスと最後のHTTPを通して、データを入出力は初体験でしたので、そちらを中心にしてまとめていきたいと思います。

javaのプログラムを使い、HTTPプロトコルを通して、データーをI/Oする練習をしました。

SimpleDateFormat

"名前/生年月日(yyyy.MM.dd)/韓国語点数/数学点数/英語点数"をScannerから入力し、
名前、年齢、全科目の総点、平均点数を出力する問題です。
(Stringの split(delimiter) メソッドの代わりに、StringTokenizer クラスを活用すること。)

問題を読み間違って、年齢を計算しませんでした。後で Calendar クラスを活用しましたが、SimpleDateFormat の使い方には慣れていないので、勉強したいと思います。

public class TestMain2 {
public static void main(String[] args) {
   Scanner sc = new Scanner(System.in);
   System.out.print("名前/生年月日(yyyy.MM.dd)/韓国語点数/数学点数/英語点数");
   String s = sc.next();
   System.out.println(s);
		
   StringTokenizer st = new StringTokenizer(s,"/");
   System.out.printf("名前 : %s\n" , st.nextToken());		

StringTokenizerを配列のように利用し、"/" を基準にして5つで分けます。
内部は、割られたのTokenがあり、 nextToken() メソッドを呼び出し、内部のTokenをFIFOで抽出することができます。

("大和" , "1993.05.05", "80", "70", "90")
nextToken() -> "大和" OUT!
("1993.05.05", "80", "70", "90")

変数は必須ではありません。

これにより、名前が出力される。

public class TestMain2 {
public static void main(String[] args) {
  
   //名前出力完了

   try {
      String bd = st.nextToken();
      SimpleDateFormat sdf= new SimpleDateFormat("yyyy.MM.dd");
      Date birthday = sdf.parse(bd);
      System.out.println(birthday);


`Date` と `SimpleDateFormat` は、セットです。
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String day = sdf.format(now)

new Date(); : Dateクラスの基本コンストラクタは、現在時間情報をリターンする。

sdf.format(Date date) : dateのオブジェクトデーターを事前に入力したformatに変換し、Stringにリターンします。

Date -> String
現在、時間データーを持っているDateクラスのオブジェクト now
nowは、yyyy-MM-ddに合わせて、変換され、文字列にリターンされます。

String -> Date
Date date = sdf.parse(String str) : StringDateに変換する。
入れたいフォーマットをSDFのsdfのコンストラクタに入れます。
その語、String strがSDFのフォーマットと一致すれば、
parseメソッドで、Dateに変換することができます。

文字列bdを "1993.08.14" だと想像しましょう。
そのあと、SimpleFormatDateのクラスsdfは、"yyyy.MM.dd" というフォーマットを指定します。
bdはsdfのフォーマットに一致しますので、parseメソッドのパラメーターに入り、
CBVによって、Dateクラスのデーターとして変換されます。

String : 1993.08.14 -> Date : Mon Aug 14 20:49:20 KST 2023

  SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy/MM/dd E");
  String birthdatStr = sdf2.format(birthday);
  System.out.printf("생일 : %s\n", birthdatStr);
			
  SimpleDateFormat yearFmt = new SimpleDateFormat("yyyy");
  String nowYr = yearFmt.format(new Date());
  int ny = Integer.parseInt(nowYr);
			
  String birthdaytYr = yearFmt.format(birthday);
  int by = Integer.parseInt(birthdaytYr);
			
  int age = ny - by;
  System.out.printf("나이 : %d살\n",age);
			
  }catch(Exception e) {
   e.printStackTrace();
   }
   sc.close();
 }
 
Mon Aug 14 20:49:20 KST 2023
2023-08-14
2023년 08월 14일
String bd = st.nextToken();
SimpleDateFormat sdf= new SimpleDateFormat("yyyy.MM.dd");
Date birthday = sdf.parse(bd);

Dateでparseしたbdを、birthdayに込めてから、活用できることがわかります。

Calendar

私の場合は、まだ、SimpleDateFormatクラスが慣れていなかったため、Calendarクラスを活用し、年齢を計算しました。

また、生年月日の場合、追加でStringTokenizerのオブジェクトを生成し、.をdelimiterに割りました。

import java.util.*;

public class TextMain {

//StringTokenizer

public static void main(String[] args) {
   Scanner sc = new Scanner(System.in);
		
   System.out.print("名前/生年月日(yyyy.MM.dd)/韓国語点数/数学点数/英語点数");
   System.out.println();
   String input = sc.next();
		
   StringTokenizer st = new StringTokenizer(input,"/");
   int total = 0;
		
   //名前
   System.out.print("이름:" + st.nextToken());
		
  //年齢 
  String birth = st.nextToken();
  StringTokenizer st2 = new StringTokenizer(birth,".");
  int inputyear = Integer.parseInt(st2.nextToken());
  int inputmonth = Integer.parseInt(st2.nextToken());		
  int inputday = Integer.parseInt(st2.nextToken());
		
  Calendar cal = Calendar.getInstance();
  int year = cal.get(Calendar.YEAR);
  int month = cal.get(Calendar.MONTH)+1;
  int day = cal.get(Calendar.DAY_OF_MONTH);
		
  //現在基準、誕生日の月が今より小さい数であれば、普通の年 
  //大きかったら-1 
	
  if(inputmonth-month >0 || inputmonth == month && inputday > day) {
	System.out.printf(" 나이:%d세", year-inputyear-1); 
  }
  else {
   	System.out.printf(" 나이:%d세", year-inputyear); 
  }
		
  //点数
  while(st.hasMoreTokens()) {
       total += Integer.parseInt(st.nextToken());
  }

  System.out.print(" 총점:" + total +"점");
  System.out.printf(" 평균:%.2f점",(double)total/3);
	    
  sc.close();
  }

}

이름/생년월일(yyyy.MM.dd)/국어점수/수학점수/영어점수
권혁모/1993.02.16/95/75/97
이름:권혁모 나이:30세 총점:267점 평균:89.00점

HTTP

Hyper Text Transfer Protocolで、意味的にはHyper Textを転送する時の規約ですが、実質的はイメージ、動画などを含めたWeb pageを転送する方式を意味します。

プロトコール(protocol)は、 規約という意味で、HTTPはOSIの7階(Application layer)に存在するプロトコールです。7階のプロトコールにはSMTPもあります。メールを送る際にの規則だと理解すればいいと思います。

www.google.comがあるとすれば、
googleに入るため、URLを入力し、エンターを押すひとがClientになります。
クライアントURLを入力し、エンターをすることがRequestになり、
それをチェックし、サーバーからクライアントに情報を提供する過程をResponseといいます。

HTTPは大きく、RequestResponseに分けることができます。
また、情報を交換する際は、HeaderEntity(Body) があり、Headerは、メタデーターを、Entity(Body)は中身だと考えばいいと分かりやすいと思います。
RequestもResponseも
Header
Entity(Body) を込めたデーターを交換します。

ClientRequest
GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

GETをする場合、Bodyがないらしいですが、こんな感じです。

GET :メソッド情報です。POSTなど他のメソッドも存在します。
index.html : ゲットしたいリソース情報です。
HTTP/1.1 : HTTP1.1というHTTPのバージョン情報です。
Host : RequestするHostのドメインの名前です。
User-Agent :クライアントの(brower)情報です。

ServerResponse
HTTP/1.1 200 OK
Date: Sun, 15 Aug 2023 12:34:56 GMT
Server: Apache
Content-Type: text/html
Content-Length: 1234

<html>
<head>
    <title>Welcome to Example</title>
</head>
<body>
    <h1>Hello, world!</h1>
</body>
</html>

header

HTTP/1.1 200 OK: レスポンスのステータスコードとメッセージを示します。ここでは「200 OK」となっており、成功のステータスであることが分かります。
Date: Sun, 15 Aug 2023 12:34:56 GMT: レスポンスが生成された日時を示します。
Server: Apache: サーバーソフトウェアの名前を示します。
Content-Type: text/html: レスポンス本文のデータタイプを示します。ここではHTML形式のデータを含んでいることが分かります。
Content-Length: 1234: レスポンス本文の長さを示します。ここでは本文の長さが1234バイトであることが示されています。

エンティティ(body)

<html> ... </html>: 実際のウェブページのHTMLコードを示します。
この部分がレスポンスの本文であり、ウェブページの内容を含んでいます。

ネットワークI/O

javaには、HTTPを通して、htmlを読み取る方法があります。
以前は、HTTPClientの機能がなかったため、apacheというサイトから提供するライブラリを活用したそうです。現在、一部のクラスはDeprecatedされており、昔はこのような方法を使ったようだなみたいな感覚で理解してくださいと言われました。

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;



public class Hmain1 {
   public static void main(String[] args) {
   try {
   
  //DefaultHttpClientのクラスからオブジェクトを生成します。
  //dhcはclientになります。
  
  DefaultHttpClient dhc = new DefaultHttpClient();
		
  //Request = GET or POST
  //サーバーに何かを要請します。
  HttpGet hg = new HttpGet("https://www.naver.com/");
		
  //サーバーから返事みたいなやつが来ます。
  HttpResponse hr = dhc.execute(hg);
		
  //その中身を入れます。
  HttpEntity he = hr.getEntity();
		
  //ストリームにその中身を込めて、出力します。
  InputStream is = he.getContent();
  InputStreamReader isr = new InputStreamReader(is,"UTF-8");
  BufferedReader br = new BufferedReader(isr);

  String line = null;
  while((line = br.readLine()) !=null) {
	System.out.println(line);
   }
		
  }catch(Exception e) {
	e.printStackTrace();
	}
  }
}

現在は、このような方法よりは、javaのライブラリより、HTTPをRequest, responseができるようです。

まず、Requestのため、必要なのはアドレスですね?
javaはそのため、java.net.URL のオブジェクトのコンストラクタにURLを入力すれば、そのURLを意味するオブジェクトが生成されます。

その後、URLを

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

public class HMain2 {
   public static void main(String[] args) {

   try {
	String address = "https://www.naver.com/";
	URL u = new URL(address);
	HttpsURLConnection huc = (HttpsURLConnection) u.openConnection();
			
	InputStream is = huc.getInputStream();
	InputStreamReader isr = new InputStreamReader(is,"UTF-8");
	BufferedReader br = new BufferedReader(isr);
			
	String line = null;
		while((line = br.readLine()) != null) {
		System.out.println(line);
		}
	}catch(Exception e) {
	 e.printStackTrace();
	}
	
   }

}

1 . URLのオブジェクト u はopenConnection()でURLConnectionをりたーンする。
2. naverはhttpsであるため、HttpsURLConnectionのオブジェクトが必要だ。
3. そのため、URLconnctionではなく、HttpsURLConnectionのオブジェクトをリターンするためにはダウンキャストする。

Discussion