반응형
java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: HourOfDay
Exception evaluating SpringEL expression: "#temporals.hour(localDateTime)"

원인 : 날짜 포맷이 맞지 않아서 오류 발생

 

<li>${#temporals.hour(localDateTime)} = <span th:text="${#temporals.hour(localDateTime)}"></span></li>
<li>${#temporals.minute(localDateTime)} = <span th:text="${#temporals.minute(localDateTime)}"></span></li>
<li>${#temporals.second(localDateTime)} = <span th:text="${#temporals.second(localDateTime)}"></span></li>
<li>${#temporals.nanosecond(localDateTime)} = <span th:text="${#temporals.nanosecond(localDateTime)}"></span></li>

시간 데이터가 필요한데 컨트롤러에서 날짜 포맷팅이 잘못된 변수를 가져오니 오류를 뱉어냈다.

 


 

1. LocalDate.now(); 

날짜 출력 ex) 2023-09-26

 

2. LocalDateTime.now();

날짜와 시간 출력 ex)  2023-09-26T16:28:36.877742300

반응형
반응형
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: org/json/JSONException

 

<!-- https://mvnrepository.com/artifact/org.json/json -->
		<dependency>
		    <groupId>org.json</groupId>
		    <artifactId>json</artifactId>
		    <version>20230227</version>
		</dependency>

 

maven으로 json 라이브러리를 사용하고 있는데 서버에 올리니 저런 오류가 뜸.

 

해결 방법 )

 

간단하게 https://mvnrepository.com/artifact/org.json/json/20230227 에서 jar파일을 다운받아 lib 폴더에 넣어주기만 했다.

반응형
반응형

postgresql에는 Oracle의 BLOB 형타입이 없다. 바이너리 데이터를 다룰려면 BYTEA 형타입을 사용해야 함.

 

1. TEXT 타입에 base64 데이터 다운로드

public static void downloadFile(HttpServletResponse response, FileVO file) {

		String fileName = file.getFile_name();
		String base64String = file.getFile_text();
		
		// Base64 인코딩된 데이터에서 "data:image/jpeg;base64," 부분을 제거
        String base64Data = base64String.substring(base64String.indexOf(",") + 1);

        // Base64 문자열을 바이너리 데이터로 디코딩
        byte[] binaryData = Base64.getDecoder().decode(base64Data);
        
        try {
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(fileName,"UTF-8") + "\"");
            OutputStream outputStream = response.getOutputStream();
            outputStream.write(binaryData);
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
}

 

2. BYTEA 타입에 바이너리 데이터 다운로드

public static void downloadFile(HttpServletResponse response, FileVO file) {

		String fileName = file.getFile_name();
        byte[] binaryData = file.getFile_contents();
        
        try {
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(fileName,"UTF-8") + "\"");
            OutputStream outputStream = response.getOutputStream();
            outputStream.write(binaryData);
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
}

 

+) VO

public class FileVO {
    private byte[] file_contents;
    private String file_text;

	~~
    
}

 

++) JPA Entity에서 bytea 타입 쓸 경우 

@Entity
@Table(name="tops_file_test")
@Getter @Setter
public class FileEntity {

    @Id
    private String FILE_ID;

    @Column(name = "file_name")
    private String file_name;

    @Type(type="org.hibernate.type.BinaryType")
    @Column(name = "file_contents", columnDefinition="bytea")
    private byte[] file_contents;

}

 

 

*파일 업로드는 MDN 참고해서 result 값을 insert 시키면 된다.

 

<핵심>

new FileReader();

fr.result 

readAsDataURL();

// Given this HTMLInputElement of type="file":
// <input id="image" type="file" accept="image/*">

function reader(file, callback) {
  const fr = new FileReader();
  fr.onload = () => callback(null, fr.result);
  fr.onerror = (err) => callback(err);
  fr.readAsDataURL(file);
}

document.querySelector("#image").addEventListener("change", (evt) => {
  // No files, do nothing.
  if (!evt.target.files) {
    return;
  }
  reader(evt.target.files[0], (err, res) => {
    console.log(res); // Base64 `data:image/...` String result.
  });
});

https://developer.mozilla.org/en-US/docs/Web/API/FileReader/result


서버에 저장된 FILE들을 바이너리 데이터로 변환하여 DB 저장

모두 SEELCT해서 for문 돌리면서 실 파일 데이터를 바이너리 데이터로 변환하여 DB에 저장

(위의 다운로드 코드로 DB SELECT해서 바이너리 데이터를 다운처리 가능)

 

나는 DB 용량 때문에 서버 경로에 저장하는게 괜찮다고 생각하지만 ,, 요구사항이 이렇다!

@RequestMapping("/fileTest")
    public void fileTest (HttpServletResponse response){
        String filePath = "C:/file_test/";

        for (FileEntity file : fileRepository.findAll()) {
            byte[] bytes = FileUtil.FileToData(filePath+file.getFILE_ID());
            file.setFile_contents(bytes);

            fileRepository.save(file);
        }

       // FileUtil.downloadFile(response, bytes);
    }
public static byte[] FileToData(String filePath) {
        byte[] fileBytes = null;
        try {
            InputStream inputStream = new FileInputStream(new File(filePath));

            fileBytes = inputStream.readAllBytes();

            System.out.println("File saved to database.");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return fileBytes;
    }
반응형
반응형

ref. holycoders

- java.util 패키지의 Collection 프레임워크

- 후입선출(LIFO : Last In First Out)

 

 

🔩 선언

Stack<String> stringStack = new Stack<String>(); // String타입

Stack<Character> charStack = new Stack<Character>(); // Char타입

Stack<Integer> integerStack = new Stack<Integer>(); // Integer타입
Stack<Integer> integerStack2 = new Stack<>(); // 뒷 부분 타입 생략 가능

Integer, String, Character 등 다양한 형타입으로 선언 가능

 

Stack stack = new Stack(); // 타입 선언 생략 가능 > Object로 선언
Stack<class> stack = new Stack<class>(); // class타입

형타입 생략 가능하지만 웬만하면 명시해주는걸로..!

 

🔩 Stack 값 추가 : push()

stack.push(5);
stack.push(6);

 

🔩 Stack 값 제거 : pop();

stack.pop();	//6 제거
stack.pop();	//5 제거

*값이 없는데 pop()을 하면 오류가 떨어지기 때문에 널체크 주의!

 

🔩 Stack 크기 구하기 : size();

stack.size()

 

🔩 Stack 값 구하기 : peek();

import java.util.*;
import java.io.*;
  
public class StackDemo {
  
      // Main Method
    public static void main(String args[])
    {
        // Creating an empty Stack
        Stack<String> stack = new Stack<String>();
  
        // Use push() to add elements into the Stack
        stack.push("Welcome");
        stack.push("To");
        stack.push("Geeks");
        stack.push("For");
        stack.push("Geeks");
        
        // Displaying the Stack
		System.out.println("Stack: " + stack);

        // Fetching the element at the head of the Stack
        System.out.println("The element at the top of the"+ " stack is: " + stack.peek());
        
     }
 }

> 결과

Initial Stack: [Welcome, To, Geeks, For, Geeks]
The element at the top of the stack is: Geeks

 

🔩 Stack 값 비우기 : clear();

🔩 Stack null 체크 : isEmpty();

 


ref. https://www.geeksforgeeks.org/stack-class-in-java/

 

Stack Class in Java - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

 

🗒 간단한 Stack 문제 풀고 싶으면 아래 문제 추천

https://www.acmicpc.net/problem/9012

 

9012번: 괄호

괄호 문자열(Parenthesis String, PS)은 두 개의 괄호 기호인 ‘(’ 와 ‘)’ 만으로 구성되어 있는 문자열이다. 그 중에서 괄호의 모양이 바르게 구성된 문자열을 올바른 괄호 문자열(Valid PS, VPS)이라고

www.acmicpc.net

 

반응형
반응형

백준 11650번 좌표 정렬하기 https://www.acmicpc.net/problem/11650

 

11650번: 좌표 정렬하기

첫째 줄에 점의 개수 N (1 ≤ N ≤ 100,000)이 주어진다. 둘째 줄부터 N개의 줄에는 i번점의 위치 xi와 yi가 주어진다. (-100,000 ≤ xi, yi ≤ 100,000) 좌표는 항상 정수이고, 위치가 같은 두 점은 없다.

www.acmicpc.net

 

arr[0][0]과 arr[1][0]의 값이 같다면 arr[0][1] 값과 arr[1][1] 값을 비교하여 작은 값을 먼저 출력하면 된다.

 

즉, 오름차순 + 오름차순

 


Arrays.sort(arr);

// I cannot be cast to class java.lang.Comparable

 2차원 배열을 이런 식으로 정렬한다면 주석과 같은 오류가 뜬다.

 

1. Comparator로 정렬

for(int i=0; i<N; i++) {
    StringTokenizer st = new StringTokenizer(br.readLine(), " ");
    arr[i][0] = Integer.parseInt(st.nextToken());
    arr[i][1] = Integer.parseInt(st.nextToken());
}

Arrays.sort(arr, new Comparator<int[]>() {
    @Override
    public int compare(int[] o1, int[] o2) {
        return o1[0]==o2[0] ? o1[1]-o2[1] : o1[0]-o2[0];
    }
});

 

2. 람다식 정렬

for(int i=0; i<N; i++) {
    StringTokenizer st = new StringTokenizer(br.readLine(), " ");
    arr[i][0] = Integer.parseInt(st.nextToken());
    arr[i][1] = Integer.parseInt(st.nextToken());
}

Arrays.sort(arr, (o1, o2) -> { return o1[0]==o2[0] ? o1[1]-o2[1] : o1[0]-o2[0]; });

람다식이 훨씬 간결한 코드로 작성된다.

 

* o1, o2의 타입이 int로 같으므로 타입을 작성하지 않아도 됨.

 


🔍간단하게 더 알아보기

 

1. Comparable  VS Comparator 

 

Comparable -  this.val 와 o.val를 비교 (자기 자신과 매개변수를 비교), compareTo 메소드 필요

Comparator - 두 매개변수를 비교

 

나의 가상 스승님이신 블로거님의 정리. 흐릿해지면 정독해

https://st-lab.tistory.com/243

 

2.  Collections.sort() 

Arrays.~~만 쓰지말고 다른 것도 써보자!

 

반응형
반응형

https://www.acmicpc.net/problem/2231

 

2231번: 분해합

어떤 자연수 N이 있을 때, 그 자연수 N의 분해합은 N과 N을 이루는 각 자리수의 합을 의미한다. 어떤 자연수 M의 분해합이 N인 경우, M을 N의 생성자라 한다. 예를 들어, 245의 분해합은 256(=245+2+4+5)이

www.acmicpc.net

 

🌌 전체 코드 (밑에 응용 버전O)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main{
	public static void main(String args[]) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		int N = Integer.parseInt(br.readLine());

		int cnt=0;
		
		for(int i=0; i<N; i++) {
			int num=i;
			int sum=0;
			
			while(num != 0) {
				sum+=num%10;	//1자리 수부터 계산하여 sum에 합계
				num/=10;		//앞자리 수 숫자 계산을 위해 10 나누기
			}
			
			if(sum+i==N) {
				System.out.println(i);
				cnt++;
				break;
			} 
		}
		
		if(cnt==0) {
			System.out.println(0);	//생성자가 없으면 0 출력
		}
	}
}

브루트포스 알고리즘은 0부터 목표 수까지 그냥 돌리면 돼서 쉬운데 코드를 짤 때 완전탐색 방식으로 짜지 않다보니 꼬이고 꼬이는 편이다.. 풀이를 보면 쉬운데 보기 전에는 혼자 우주까지 가버린다. 여러 문제를 풀면 쉽게 풀릴거 같으니 문제를 많이 풀어봐야겠다.

 

완탐 방식을 생각못하고 효율적으로 짜야겠다며 처음엔 236이 주어지면 2이하, 3이하, 6이하의 숫자만 올 수 있어서 이를 코드로 녹이려고 했는데 중첩의 중첩 반복문이 될 아이디어였다.

 

해당 코드는 나의 가상스승님이신 블로거님 코드를 참고하였다.

https://st-lab.tistory.com/98

 

[백준] 2231번 : 분해합 - JAVA [자바]

www.acmicpc.net/problem/2231 2231번: 분해합 문제 어떤 자연수 N이 있을 때, 그 자연수 N의 분해합은 N과 N을 이루는 각 자리수의 합을 의미한다. 어떤 자연수 M의 분해합이 N인 경우, M을 N의 생성자라 한다

st-lab.tistory.com


for(int i=0; i<N; i++) {
    int num=i;
    int sum=0;

    while(num != 0) {
        sum+=num%10;	//1자리 수부터 계산하여 sum에 합계
        num/=10;		//앞자리 수 숫자 계산을 위해 10 나누기
    }

    if(sum+i==N) {
        System.out.println(i);
        cnt++;
        break;
    } 
}

 

백준 예제로 실행해본다고 가정

while(num!=0){
    sum+=num%10;
    num/=10;
}

> num = 198 일 때,

 

1) sum = 8; num = 19;

sum+=198%10;

num/=10;

 

2) sum = 17; num = 1;

sum+=19%10;

num/=10;

 

2) sum = 18; num = 0;

sum+=1%10;

num/=10;

 

if(sum+i==N) {
    System.out.println(i);
    cnt++;
    break;
}

18+198 = 256;

생성자가 없을 경우를 생각해서 카운팅하고

제일 작은 수의 생성자를 출력해야하기 때문에 break문으로 for문을 탈출

 


🌌 전체 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main{
	public static void main(String args[]) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		String strN = br.readLine();
		int str_len = strN.length();	//N의 자릿수
		int N = Integer.parseInt(strN);	//int로 형타입 변환
		int cnt=0;
		
		for(int i=N-(str_len*9); i<N; i++) {
			int num=i;
			int sum=0;
			
			while(num != 0) {
				sum+=num%10;	//1자리 수부터 계산하여 sum에 합계
				num/=10;		//앞자리 수 숫자 계산을 위해 10 나누기
			}
			
			if(sum+i==N) {
				System.out.println(i);
				cnt++;
				break;
			} 
		}
		
		if(cnt==0) {
			System.out.println(0);
		}
	}
}

처음엔 이게 무슨 소리지 했다. 근데 겁나 간단함.

 

예를들어, 1234와 같은 4자리 수가 N으로 주어진다면

자릿수 별 합은 9+9+9+9가 최대가 되기 때문에 최댓값 9와 자릿수를 곱해야한다.

이를 N에서 빼면 최소 N-(str_len*9)부터 N까지의 숫자만 생성자가 될 수 있다.

 

생성자가 될 수 있는 최솟값은 1234-(9*4)인 것.

1234의 생성자 x를 구할 때

36+x = 1234니깐! x=1234-36!! 

for(int i=N-(str_len*9); i<N; i++) {
	...
 }

 

반응형
반응형

https://www.acmicpc.net/problem/1259

 

1259번: 팰린드롬수

입력은 여러 개의 테스트 케이스로 이루어져 있으며, 각 줄마다 1 이상 99999 이하의 정수가 주어진다. 입력의 마지막 줄에는 0이 주어지며, 이 줄은 문제에 포함되지 않는다.

www.acmicpc.net

 

🌌 전체 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main{
	public static void main(String args[]) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder sb = new StringBuilder();
		StringBuilder sb2 = new StringBuilder();
		String str = "";

		while ((str = br.readLine()) != null && (Integer.parseInt(str) != 0)) {
			sb.setLength(0); //sb 객체 비우기
			String strReverse = sb.append(str).reverse().toString();

			if(str.equals(strReverse)) {
				sb2.append("yes" + "\n");
			} else {
				sb2.append("no" + "\n");
			}
		}
		System.out.println(sb2);
	}
}

나는 이 문제에서 StringBuilder를 적극 활용했다.

 

1. for문 배열 길이 신경 쓰기보다 EOF 체크를 하면서  while문을 돌렸고 0이라면 while문을 실행X

while ((str = br.readLine()) != null && (Integer.parseInt(str) != 0)) {
	...
}

 

2. sb 객체를 비우고 reverse() 메소드를 활용하여 input된 값과 비교

while ((str = br.readLine()) != null && (Integer.parseInt(str) != 0)) {
    sb.setLength(0); //sb 객체 비우기
    String strReverse = sb.append(str).reverse().toString();

    if(str.equals(strReverse)) {
        sb2.append("yes" + "\n");
    } else {
        sb2.append("no" + "\n");
    }
}

 

* 너무 간단하게 풀려서 다른 풀이를 확인해봤는데 역배열을 하여 비교하거나 배열의 반틈만 비교하는 방법이 있었다.

반응형
반응형

 

https://school.programmers.co.kr/learn/courses/30/lessons/42746

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

    int len = (int) (Math.log10(numbers[i])+1); //자릿수
    if(len >= 2){
        a = numbers[i]/(1*(10*(len-1))); //앞자리 숫자
    } else {
        a = numbers[i];
    }

앞자리 수만 비교해서 정렬 후 앞자리가 같으면 뒷자리 정렬하면 되겠지 생각했다.

처음엔 삽질 너무 많이 하다가 안되겠다 싶고 이걸 풀어도 시간초과나겠다 싶어서 결국 구글링.,,.,

 


🌌 전체 코드

import java.util.Arrays;

class Solution {
    public String solution(int[] numbers) {
        StringBuilder sb = new StringBuilder(); 
        String[] arr = new String[numbers.length];
        
        for(int i=0; i<numbers.length; i++){
            arr[i] = Integer.toString(numbers[i]);
        }
        
        Arrays.sort(arr, (String o1, String o2) -> (o2+o1).compareTo(o1+o2));
        
        if(arr[0].equals("0")){ return "0"; }
        
        for(String val : arr) sb.append(val);
        
        return sb.toString();
    }
}

1. String 배열로 요소들을 다 넣어준다.

 

(처음 시도엔 int로 처리하고 결과 값을 String으로 형변환해주려고 했는데 이건 너무 멀리가야했음)

StringBuilder sb = new StringBuilder(); 
String[] arr = new String[numbers.length];

for(int i=0; i<numbers.length; i++){
    arr[i] = Integer.toString(numbers[i]);
}

 

 

2. compareTo 사용하여 비교 

그냥 정렬하게 될 경우 6102가 반환되는데, 6102 < 6210 이므로

각각 더 한 값을 비교하여 큰 값을 리턴한다.

아래 코드 후 arr를 출력해보면 [6, 2 , 10]으로 출력된다.

 

compareTo!!

람다식을 활용하면 코드를 간결하게 작성할 수 있다. 니꼬 js강의 들을 때 람다식으로 많이 써서 그나마 익숙해졌다!

Arrays.sort(arr, (String o1, String o2) -> (o2+o1).compareTo(o1+o2));

이 부분만 알면 간단한 문제였다,,

 

Arrays.sort(arr, new Comparator<String>(){
    @Override
    public int compare(String a, String b){
        return (b + a).compareTo(a + b);
    }
});

이런 식으로도 쓸 수 있는데 완벽하게 Comparator를 잘 몰라서 더 알아봐야 할 것 같다.

그리고 Collections.sort(); 을 활용한 분도 계셨는데 이것도,, ( 리스트를 사용하심 List<Integer> list = new ArrayList<>();  )

 

 

3. 앞자리가 0이라면 0을 반환

 

0000이라면 0을 출력해야하니깐

if(arr[0].equals("0")){ return "0"; }

 

4. 출력 

for(String val : arr) sb.append(val);

return sb.toString();
반응형