레이블이 자바인 게시물을 표시합니다. 모든 게시물 표시
레이블이 자바인 게시물을 표시합니다. 모든 게시물 표시

2019년 3월 12일 화요일

FCM 전송 예제

- GCM은 사용하지 말것.
https://developers.google.com/cloud-messaging/

- FCM 레퍼런스 :
https://firebase.google.com/docs/cloud-messaging/migrate-v1?hl=ko

- 예제소스는 HTTP v1 샘플소스

- 메시지 포멧은 JSON 이므로 JSON 라이브러리를 사용을 권장.



1. 메시지 전송
- 기본코드
String urlStr = "https://fcm.googleapis.com/fcm/send";
String authorization = "key=[클라우드 메시지 서버 키]";

String token = "[클라이언트 FCM 토큰]";
String data = "\"data\": {\r\n" + " \"en\": \"abc\",\r\n" + " \"ko\": \"가나다\"\r\n" + " }";
String notification = "\"notification\" : {\r\n"
        + " \"body\" : \"This is an FCM notification message!\",\r\n"
        + " \"title\" : \"FCM Message\"\r\n" + " }";

URL url = null;
HttpURLConnection connection = null;
BufferedOutputStream bos = null;
BufferedReader reader = null;

try {
    url = new URL(urlStr);
    connection = urlStr.startsWith("https://") ? (HttpsURLConnection) url.openConnection()
            : (HttpURLConnection) url.openConnection();
    connection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
    connection.setRequestProperty("cache-control", "no-cache");
    connection.setRequestProperty("Authorization", authorization);

    connection.setDoOutput(true);
    connection.setDoInput(true);

    connection.connect();

    bos = new BufferedOutputStream(connection.getOutputStream());

    String message = "{\"to\" : \"" + token + "\"," + data + "," + notification + "}";
    bos.write(message.getBytes("UTF-8"));

    bos.flush();
    bos.close();

    int responseCode = connection.getResponseCode();
    String responseMessage = connection.getResponseMessage();
    StringBuffer buffer = null;
    if (responseCode == HttpURLConnection.HTTP_OK) {

        buffer = new StringBuffer();
        reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
        String temp = null;
        while ((temp = reader.readLine()) != null) {
            buffer.append(temp);
        }
        reader.close();
    }
    connection.disconnect();
    System.out.println(String.format("Response : %d, %s", responseCode, responseMessage));
    System.out.println("Response DATA : ");
    System.out.println(buffer == null ? "NULL " : buffer.toString());
} catch (IOException e) {
    e.printStackTrace();
}


> POST 전송 방식
> data만 사용하면 항상 백그라운드 서비스가 메시지를 수신
> notification을 적용할 경우 Activity가 Foreground 상태일 때와 Background 상태일 때 응답 방식이 변경됨.
> 한글깨짐 문제가 될 수 있으므로 UTF-8 인코딩을 적용.

2019년 3월 8일 금요일

동기화 예제 - synchronized

- 자바 동기화(synchronized) 기본 예


1. 문제가 되는 코드
- 기본 코드
public class SimpleSynchronized {

int balance = 100000000;
int count1 = 0;
int count2 = 0;

public int getBalance() {
return balance;
}

public void addBalance(int balance) {
this.balance += balance;
}

public static void main(String[] args) {
final SimpleSynchronized simpleSynchronized = new SimpleSynchronized();
new Thread() {

@Override
public void run() {
while (simpleSynchronized.getBalance() >= 1000) {
simpleSynchronized.addBalance(-1000);
simpleSynchronized.count1++;
}

System.out.println("Thread 1 : " + simpleSynchronized.count1);
}

}.start();

new Thread() {

@Override
public void run() {
while (simpleSynchronized.getBalance() >= 1000) {
simpleSynchronized.addBalance(-1000);
simpleSynchronized.count2++;
}
System.out.println("Thread 2 : " + simpleSynchronized.count2);
}

}.start();

new Thread() {

@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("balance : " + simpleSynchronized.balance);
System.out.println("count total : " + (simpleSynchronized.count1 + simpleSynchronized.count2));
}

}.start();
}
}

- 결과
Thread 2 : 13312
Thread 1 : 89300
balance : -1000
count total : 102612

> 쓰레드1과 쓰레드2가 동일한 시간에 balance 값이 1000 보다 큰 경우만 -1000을 하면 결과적으로 1000 > 0 > -1000이 되는 문제가 발생한다.
> 루프 카운트도 100000000 / 1000 번을 하는 것이 아닌 것이 확인된다.


2. synchronized 적용
- 기본코드
public class SimpleSynchronized {

int balance = 100000000;
int count1 = 0;
int count2 = 0;

public int getBalance() {
return balance;
}

public void addBalance(int balance) {
this.balance += balance;
}

public static void main(String[] args) {
final SimpleSynchronized simpleSynchronized = new SimpleSynchronized();
new Thread() {

@Override
public void run() {
synchronized (simpleSynchronized) {
while (simpleSynchronized.getBalance() >= 1000) {
simpleSynchronized.addBalance(-1000);
simpleSynchronized.count1++;
}
}
System.out.println("Thread 1 : " + simpleSynchronized.count1);
}

}.start();

new Thread() {

@Override
public void run() {
synchronized (simpleSynchronized) {
while (simpleSynchronized.getBalance() >= 1000) {
simpleSynchronized.addBalance(-1000);
simpleSynchronized.count2++;
}
System.out.println("Thread 2 : " + simpleSynchronized.count2);
}
}

}.start();

new Thread() {

@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("balance : " + simpleSynchronized.balance);
System.out.println("count total : " + (simpleSynchronized.count1 + simpleSynchronized.count2));
}

}.start();
}
}

- 결과
Thread 2 : 0
Thread 1 : 100000
balance : 0
count total : 100000

> 쓰레드2는 쓰레드1이 simpleSynchronized 객체를 동기화 하기 때문에 쓰레드1의 작업이 완료되기 전까지 대기 한다.
> synchronized는 동기가 필요한 곳에 적절하게 적용해야 한다.
> 주된 예로 다중쓰레드 환경에서 Map 객체의 put과 remove를 synchronized없이 처리하면 문제가 되는 경우가 있다.





3. 동기화 기본 문법
- 객체 동기화
Object object = new Object();
synchronized (object) {

}

synchronized (this) {

}

> 기본변수(int, long, double 등) 타입은 적용 불가.

- 클래스 단위의 동기화
synchronized (Object.class) {

}

- 메소드 동기화
public synchronized void setObject(Object object) {

}

Restful API 예제코드 - HttpURLConnection

1. Restful API - HttpURLConnection
- 기본코드
String urlStr = "https://www.instagram.com/web/search/topsearch/?context=blended&query=java";
URL url = null;
HttpURLConnection connection = null;
BufferedReader reader = null;

try {
url = new URL(urlStr);
connection = urlStr.startsWith("https://") ? (HttpsURLConnection) url.openConnection() : (HttpURLConnection) url.openConnection();

connection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
connection.setRequestProperty("cache-control", "no-cache");

connection.connect();

int code = connection.getResponseCode();
String message = connection.getResponseMessage();

StringBuffer buffer = null;
if (code == HttpURLConnection.HTTP_OK) {
buffer = new StringBuffer();

reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
String temp = null;
while ((temp = reader.readLine()) != null) {
buffer.append(temp);
}

reader.close();
}
connection.disconnect();

System.out.println(String.format("Response : %d, %s", code, message));
System.out.println("Response DATA : ");
System.out.println(buffer == null ? "NULL " : buffer.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


- 결과
Response : 200, OK
Response DATA :
{}


> URL 문자열에서 HTTPS를 판단해서 캐스팅 할 클래스를 선택
> Restful API 사양에 맞는 RequestHeader 설정
> 예제코드에서 사용한 Restful API 주소는 인스타그램 검색 API

2019년 3월 6일 수요일

칼만필터 예제

1. 기본코드
public class Kalman {
    private static final double Q = 0.00001;
    private static final double R = 0.001;

    private double P = 1;
    private double X = 0;
    private double K;


    public Kalman(double value) {
        X = value;
    }

    // 계산
    private void measurementUpdate() {
        K = (P + Q) / (P + Q + R);
        P = R * (P + Q) / (P + Q + R);
    }

    // 현재값을 받아 계산된 공식을 적용하고 반환한다
    public double update(double measurement) {
        measurementUpdate();
        X = X + (measurement - X) * K;
        return X;
    }

}

- 상수 Q와 R의 이해가 필요
- 주 사용처 : 센서(온도, 습도, 자기장, 가속도계), RSSI 시그널 등의 오차 계산
- 칼만필터 위키백과 :
https://ko.wikipedia.org/wiki/%EC%B9%BC%EB%A7%8C_%ED%95%84%ED%84%B0

2019년 3월 5일 화요일

외부 프로세스 실행하기 - 자바


1. 프로세스 실행 - Process
- 메모장 실행 코드
try {
String command = "notepad";
Process process = Runtime.getRuntime().exec(command);
try {
process.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
process.destroy();
} catch (IOException e) {
e.printStackTrace();
}


- 결과
메모장 프로세스가 호출되면 process.waitFor(); 메소드에서 대기.
메모장 프로세스가 종료되면 process.destroy(); 메소드를 호출하고 종료.




2. 프로세스 출력 가져오기
- 실행코드
try {
String command = "cmd";
Process process = Runtime.getRuntime().exec(command);
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "949"));

String temp = null;
while ((temp = reader.readLine()) != null) {
System.out.println(temp);

}
reader.close();
process.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
process.destroy();
} catch (IOException e) {
e.printStackTrace();
}

- 결과
cmd는 출력 후 종료되는 방식이 아니므로 process.waitFor(); 메소드에서 대기.
keytool 실행 프로세스를 이용해서 테스트 해보면 process.destroy(); 까지 정상적으로 실행됩니다.

Hex.decodeHex - 바이트문자열 변환

- Hex.decodeHex를 통한 byteString을 정수형으로 변환하는 샘플.



1. 기본 예제
String value = "ff";

try {
byte[] bytes = Hex.decodeHex(value);
long result = bytes[0] & 0xff;

System.out.println(result);
} catch (DecoderException e) {
e.printStackTrace();
}

> 결과 : 255
> 0xff 마스크를 적용하지 않으면 -1 결과가 나옴.
> 2의 보수 위키백과 :
https://ko.wikipedia.org/wiki/2%EC%9D%98_%EB%B3%B4%EC%88%98







2. 변환 응용
- long 데이터로 변환 예제
String value = "FF7FFFFFFF";

try {
byte[] bytes = Hex.decodeHex(value);
long result = 0;

for (int i = bytes.length - 1; i >= 0; i--) {
result += (long) (bytes[i] & 0xff) << 8 * i;

}

System.out.println(result);
} catch (DecoderException e) {
e.printStackTrace();
}

> 결과 : 1099511595007
> int형 양수 최대 길이는 7FFFFFFF

String.format 예제 - 자바

- 자바 기준 예제
- 자주 사용하는 예제



1. 기본
- int, long
long value = 123456789;
System.out.println(String.format("%d", value));

System.out.println(String.format("%20d", value));
> 길이지정 결과 출력


- float, double
double value = 12345.6789;
System.out.println(String.format("%f", value));


- 문자열
String value = "ABC";
String value2 = "가나다";
System.out.println(String.format("%s, %s", value, value2));

System.out.println(String.format("%5s, %5s", value, value2));
> 길이지정 결과 출력




- Object
List<Object> list = new ArrayList<>();
list.add("ABC"); list.add(123);
list.add(456.789);

System.out.println(String.format("%s", list));
> toString()이 구현된 형태로 출력


- 배열
Arrays.asList을 이용
System.out.println(String.format("%s", Arrays.asList(new String[] { "123", "가나다" })));


- byte
int value = 65535;
System.out.println(String.format("%x", value));
System.out.println(String.format("%X", value));
System.out.println(String.format("%02X", value));





2. 자리수
- 콤마
double value = 12345.6789;
System.out.println(String.format("%,f", value));
System.out.println(String.format("%,d", (int)value));
> 정수는 d, 소수는 f로 적용


- 소수점 자르기(소수점 표현 지정)
double value = 12345.6789;
System.out.println(String.format("%.6f", value));
> 비는 소수점 자리는 0으로 채움







2016년 11월 12일 토요일

자바 String 기본 예제 - 문자열 다루기

1. 문자열 포함 - contains
System.out.println("ABCD123".contains("CD"));



2. 시작문자열 - startsWith
System.out.println("https://www.google.com".startsWith("https://"));



3. 끝 문자열 - endsWith
System.out.println("image.jpg".endsWith(".jpg"));



4. 비교 - equals, equalsIgnoreCase
- 대소문자 구분
System.out.println("image.jpg".equals("image.jpg"));

- 대소문자 무시
System.out.println("image.jpg".equalsIgnoreCase("IMAGE.jpg"));



5. 문자열 자르기 - substring
- index 부터 자르기
System.out.println("www.google.com".substring(3));
> 결과 : google.com

- 구간 자르기
System.out.println("www.google.com".substring(4, 10));
> 결과 : google



6. 문자열 위치 찾기 - indexOf, lastIndexOf
- 왼쪽 기준에서 위치 찾기
System.out.println("www.google.com".indexOf("google"));

- 오른쪽 기준에서 위치 찾기
System.out.println("www.google.com".lastIndexOf(".com"));


예) 구간 자르기와 함께 쓰기
String value = "www.google.com";
int beginIndex = value.indexOf(".") + 1;
int endIndex = value.lastIndexOf(".");
System.out.println(value.substring(beginIndex, endIndex));

> 결과 : google
> +1을 하는 이유 : 10 11 12 13 m



7. 정규식 - matches
- 특정 문자가 포함되는 여부 판단
System.out.println("Qwer123".matches(".*[a-z][A-Z].*"));
> 대소문자 포함 여부 확인



8. 문자열 분리(배열) - split
System.out.println(Arrays.asList("www.google.com".split("\\.")));
> 결과 : [www, google, com]



9. 문자열 바꾸기 - replace, replaceAll
- 바꾸기
System.out.println("www.google.com".replace("www", "https://www"));

- 모두 바꾸기
System.out.println("w w w . g o o g l e . c o m".replaceAll(" ", ""));
> 공백 모두 제거



10. 대소문자 변경 - toLowerCase, toUpperCase
- 모두 소문자
System.out.println("www.google.com".toLowerCase());

- 모두 대문자
System.out.println("www.google.com".toUpperCase());

소수 구하기 예제 - 素數, prime number

- 소수
1과 그수 자신 이외의 자연수로는 나눌 수 없는, 1보다 큰 자연수


1. 소스코드
public class PrimeNumber {

public static void main(String[] args) {
for (long i = 1; i < Long.MAX_VALUE; i++) {
check(i);
}
}

public static void check(long value) {
for (long i = 2; i < value; i++) {
if (value % i == 0)
return;
}
System.out.println(value);
}
}

2. 결과
1
2
3
5
7
11
13
17
19
23
29
31
...

소스코드 - 구구단

- 심심해서 짜보는 구구단 소스


1. for문 2개로 출력하기
public static void step1() {
for (int i = 2; i <= 9; i++) {
for (int j = 1; j <= 9; j++) {
System.out.println(i + " * " + j + " = " + (i * j));
}
System.out.println();
}
}



2. for문 1개로 출력하기
public static void step2() {
for (int i = 2, j = 1; i <= 9; j++) {
System.out.println(i + " * " + j + " = " + (i * j));

if (j == 9) {
j = 1;
i++;
System.out.println();
}
}
}



3. 재귀호출을 이용한 방법 - for문 없음.
public static void step3(int i, int j) {
if (i > 9)
return;

System.out.println(i + " * " + j + " = " + (i * j));
if (j < 9) {
j++;
step3(i, j);
} else {
System.out.println();

j = 1;
i++;
step3(i, j);
}
}