반응형

버전 : 자바17

내 컨트롤러 메소드..

@GetMapping(value = "/info/{a1}")
    public void getInfo(@PathVariable String a1) throws Exception {
}

이 api를 호출하면 아래와 같은 에러가 나는 것이었다

java.lang.IllegalArgumentException: Name for argument of type [java.lang.String] not specified, and parameter name information not found in class file either.

 

path parameter와 변수명이 같으면 name을 명시 안 해줘도 되는걸로 알고있었는데

컴파일 모드가 debug 모드가 아닌 경우 컴파일 시 로컬 지역변수가 포함이 안 되어 변수 맵핑을 못 한다고 함.

 

컨트롤러 메소드에 name옵션 추가해줌.. 

@GetMapping(value = "/info/{a1}")
    public void getInfo(@PathVariable(name="a1") String a1) throws Exception {
}

 

아니면 컴파일 시 지역변수 포함하도록 build.gradle 파일을 손봐준다.

셋중에 하나 추가 

java {
    options.compilerArgs << "-g"
}


tasks.withType(JavaCompile) {
   options.compilerArgs.add("-parameters")
}


compileJava {
    options.compilerArgs <<  '-parameters'
}

 

반응형
반응형

파일 확장자를 바꾸고 업로드 하는 경우 파일타입을 체크하기 위해 MIME타입 확인이 필요하게 되었다.

tika 라이브러리를 사용하였다.

MimeTypesFileTypeMap도 사용해봤는데 application/octet-stream만 반환해서 집어치웠음.

* 개발환경 : java7

* pom.xml에 의존성추가

<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>1.17</version>
</dependency>

 

Tika 객체를 생성해서 detect 메소드 사용

Tika tika = new Tika();
File file = new File("d:\\example\\file.txt")
String type = tika.detect(file);
System.out.println("type : " + type);

이미지 파일로 테스트 해 본 결과 아래와 같은 type들을 반환해주었다.

image/bmp
image/jpeg
image/png

반응형
반응형

환경) 백엔드와 프론트엔드가 분리되어있음

 

첫번째방법

PrintWriter 를 사용하여 script를 뿌려준다. javascript 소스를 텍스트로 넣으면 된다.

location.href='리다이렉트 시킬 주소'

@RequestMapping(value = "/redirect1")
    public void redirect1(HttpServletRequest request, HttpServletResponse response,
            @RequestParam Map<String, Object> paramMap,Model model) throws Exception {
        PrintWriter out = new PrintWriter(response.getWriter());
        out.println("<!DOCTYPE html>");
        out.println("<html>");
        out.println("<meta charset=\"UTF-8\" />");
        out.println("<title>TITLE입니다.</title>");
        out.println("<head>");
        out.println("</head>");
        out.println("<body>");
        out.println("<script type='text/javascript'>");
        out.println("alert('경고~~');");
        out.println("location.href='https://www.google.com';");
        out.println("</script>");
        out.println("</body>");
        out.println("</html>");
        return null;
    }

 

 

두번째방법

HTTP 응답 상태 코드 301 Moved Permanently를 사용한다.

ResponseEntity를 리턴해주는 경우 상태코드를 Moved Permanently로 설정하고 

헤더에 리다이렉트시킬 url을 적어준다. 

@RequestMapping(value = "/redirect2")
    public ResponseEntity redirect2(@RequestBody Map<String, Object> paramMap)
            throws Exception {
        return ResponseEntity
                .status(HttpStatus.MOVED_PERMANENTLY)
                .contentType(MediaType.APPLICATION_JSON)
                .header("location", "http://localhost:8081/redirect2")
                .body("message");
    
}

 

세번째방법

서버페이지를 리턴해주고 서버페이지의 script에서 location.href에 리다이렉트 시킬 url을 적어준다.

@RequestMapping(value = "/redirect1")
    public void redirect1(HttpServletRequest request, HttpServletResponse response) throws Exception {
        return "serverPage/index";
    }
<script type="text/javascript">
    parent.parent.location.href="[[${clientUrl}]]";
</script>
반응형
반응형

JAVA로 

HttpServletRequest를 받을 때 charset을 설정하는 방법

request.setCharaterEncoding("charset이름");

@RequestMapping(method = RequestMethod.POST,path = "/result")
public String result(HttpServletRequest request, HttpServletResponse response,Model model) {
        try {
            request.setCharacterEncoding("EUC-KR"); 
            HashMap<String, String> map = new HashMap<>();
            map.put("P_STATUS", request.getParameter("P_STATUS"));
            map.put("P_RMESG1", request.getParameter("P_RMESG1"));
        }catch(Exception e){
            e.printStackTrace();
        }
        return "form";
}
반응형
반응형

java로 https 통신 연결하기 / java로 api 호출하기 / java post http 

//파라미터 담기
String strParam = "param1=apple&param2=banana&param3=grape";

// 요청 URL
reqUrl = "https://www.test.com/api1/api1_2";

//결과값 담을 변수
String returnStr 	   = "";

HttpsURLConnection con = null;

try {
 	URL url = new URL(reqUrl);
          
	StringBuffer buf = new StringBuffer();

	con = (HttpsURLConnection)url.openConnection();
    
	//http method 설정
	con.setRequestMethod("POST");
    
	//서버통신 timeout 설정 (30초)
	con.setConnectTimeout(30000);
    
	//스트림읽기 timeout 설정 (30초)
	con.setReadTimeout(30000);
    
	//헤더설정
	con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
	con.setRequestProperty("Authorization", "sdfsdfsdfsdf");

	//OutputStream으로 POST 데이터 전달 옵션
	con.setDoOutput(true);

	//연결
	con.connect();

	// 송신할 데이터 전송.
	DataOutputStream dos = new DataOutputStream(con.getOutputStream());
	dos.writeBytes(strParam);
	dos.flush();
	dos.close();
    
	//응답 읽기
	StringBuilder response = new StringBuilder();
	BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(con.getInputStream()));
	
	String line;
	while ((line = bufferedReader.readLine()) != null) {
		response.append(line);
	}
	bufferedReader.close();
	returnStr = response.toString();
    
} catch (Exception e) {
		e.printStackTrace();
} finally {
		//연결종료
		if (con != null) con.disconnect();
}
반응형
반응형

필요한 내용은 다음과 같다.

1. post 메소드로 요청하는 경우 

헤더 생성 + uri 생성 + body부 데이터 생성 => RestTemplate 으로 url 요청하기

 

2. GET 메소드로 요청하는 경우

헤더 생성 + uri 생성(파라미터가 있는 경우 붙여준다) => RestTemplate으로 url 요청하기

//ResTemplate 생성
RestTemplate restTemplate = new RestTemplate();

//헤더 생성
HttpHeaders headers = new HttpHeaders();
headers.add("Accept", "*/*");
headers.add("Content-Type", "application/json;charset=UTF-8");

//url 생성
URI url = URI.create("http://localhost:8888/api/test");

//POST로 보내는 경우 : body에 실어보낼 json데이터 생성
JSONObject jsonReq = new JSONObject();
jsonReq.put("data1", "data1");
jsonReq.put("data2", "data2");
HttpEntity<String> entity = new HttpEntity<>(jsonReq.toString(), headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);

//GET으로 보내는 경우 : 쿼리파라미터는 url에 붙여 보내면 댐
RequestEntity<String> req = new RequestEntity<>(headers, HttpMethod.GET, url);
ResponseEntity<String> res = restTemplate.exchange(req, String.class);
반응형
반응형

JSON obejct는 아래 의존성을 사용하였음

org.json은 사용해봤는데 이건 또 첨 사용해봄..

		<dependency>
			<groupId>com.googlecode.json-simple</groupId>
			<artifactId>json-simple</artifactId>
			<version>1.1</version>
		</dependency>

 

URL 요청 시 응답 결과는 아래와 같음

<200,{"result":0,"data":[
{"category":"animal","type":"tiger","name":{"girl":"tigirl","boy":"tiboy"},count":"2},
{"category":"animal","type":"pig","name":{"girl":"pigirl","boy":"pigboy"},"count":2}
]

 

URL 요청 및 응답 파싱하기.

//요청할 URL의 헤더 생성
HttpHeaders headers = new HttpHeaders();
headers.add("Accept", "application/json");
headers.add("Content-Type", MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8");

//요청할 URL 생성
URI Url = URI.create("https://testsite.co.kr/api");

//요청
RequestEntity<String> requestEntity = new RequestEntity<>(headers, HttpMethod.GET, Url);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<JSONObject> responseEntity = restTemplate.exchange(requestEntity, JSONObject.class);

//응답 파싱
JSONObject responseJSON = responseEntity.getBody();
//body에서 "data"부분을 JSON Array로 파싱
JSONArray responseArray = new JSONArray(){{ addAll((Collection)responseJSON.get("data"));}};

ObjectMapper objectMapper = new ObjectMapper();
List<JSONObject> dataList = new ArrayList<>();

for(Object obj  : responseArray){
	//JSONArray에서 꺼낸 각 JSON을 obj-> Map 으로 변환시켜 사용한다.
	Map<String,Object> tmpMap= (Map) obj;
	Map<String,Object> listMap = objectMapper.convertValue(tmpMap.getOrDefault("name",null),Map.class);

	if(listMap != null) {
		listMap.put("myList", tmpMap.get("type"));
		JSONObject resultObj = new JSONObject(){{ putAll(listMap);}};
	}
}

 

JSONArray에 add 하기  addAll(Collection)
JSONObject에 put하기 putAll(Map)

json-simple은 첨이라 사용법이 익숙해지질 않음

반응형
반응형

SHA256 알고리즘을 사용한 해시함수.

메시지 다이제스트를 문자열로 return 하는 경우의 메소드와

바이트 배열로 return 하는 두 가지 경우를 생성함.

public class Sha256EncryptUtil {

public static String ShaEncoder(String userPw) {
    try {
	//알고리즘은 SHA256으로 하여 MessageDigest 객체 생성
      MessageDigest digest = MessageDigest.getInstance("SHA-256");
      //해시된 데이터는 바이트 배열의 바이너리 데이터임.
      byte[] hash = digest.digest(userPw.getBytes(StandardCharsets.UTF_8));

      StringBuilder hexString = new StringBuilder();
	  //바이트 배열을 16진수(hex) 문자열로 변환
      for (byte b : hash) {
      	//byte 8비트 ->int 32bit 형변환 시 앞의 18비트가 19번째 비트와 같은 값으로 채우는데 
        //이 경우에 원본 값과 다른 경우가 되는 것을 방지하기 위한 연산
        String hex = Integer.toHexString(0xff & b);
        if (hex.length() == 1) {
          hexString.append('0');
        }
        hexString.append(hex);
      }
      return hexString.toString();
    } catch (Exception ex) {
      throw new RuntimeException(ex);
    }
}


public static byte[] shaEncoderByte(String message){
//이 메소드는 바이트배열을 16진수 문자열로 변환하지 않음
    try {
      MessageDigest digest = MessageDigest.getInstance("SHA-256");
      byte[] hash = digest.digest(message.getBytes(StandardCharsets.UTF_8));
      return hash;
    }catch(Exception ex){
      throw new RuntimeException(ex);
    }

  }
}
반응형
반응형

우선 위경도 표현에는 두 가지 방식이 있다..

  • 소수점표현(DD,Decimal Degree) : 예) 37.397
  • 도분초 표현(DMS, Degree Minutes Seconds) 예) 37º 23' 49.2"

소수점 표현같은 경우에는 구글지도에서 쉽게 확인 가능..


1. 소수점 표현 방식 -> DMS 표현방식 변환

예) 37.397 을 DMS 표현으로 변환

  • 도 :  소수점 좌표 값의 정수(37)
  • 분 : 37을 제외한 0.397 X 60 = 23.82 에서 소수점 앞의 정수(23)
  • 초 : 0.82 X 60 = 49.2 에서 소수점 포함 앞의 4자리(49.2)

=> 37º 23' 49.2"

//소수점 표현 위도,경도를 DMS 표현으로 변환
public HashMap<String ,Object> getDmsByLatLon(Object data) throws Exception{
//data = 37.397

    HashMap<String,Object> result = new HashMap<>();
    
    try {
    
      String[] dataArray = data.toString().split("\\.");
      //도 : 소수점 좌표 값의 정수
      String dataDegree = dataArray[0];

      String dataMinutesFull = String.valueOf(Double.parseDouble("0." + dataArray[1]) * 60);
      //분
      String dataMinutes = dataMinutesFull.split("\\.")[0];
      
      
      //초
      String dataSeconds;
      if(String.valueOf(Double.parseDouble("0." + dataMinutesFull.split("\\.")[1]) * 60).length()<5){
        dataSeconds = String.valueOf(Double.parseDouble("0." + dataMinutesFull.split("\\.")[1]) * 60);
      }else {
        dataSeconds = String.valueOf(Double.parseDouble("0." + dataMinutesFull.split("\\.")[1]) * 60).substring(0, 5);
      }
      
      result.put("degree", dataDegree);
      result.put("minutes", dataMinutes);
      result.put("seconds", dataSeconds);

    }catch(Exception e){
      e.printStackTrace();
    }
    
    return result;
}
//result = {seconds=49.19, minutes=23, degree=37}

 

 

2. DMS  표현 방식 ->  소수점 표현 방식 변환

예) 37º 23' 49.2" 를 DD 표현으로 변환하기

식은 다음과 같다..

도 + ( 분 + (초 / 60 ) ) / 60

37 + ( 23 + (49.2/60) ) /60 = 37.397

double latDD = MaxDeg + (latMin + latSec / 60) / 60;

 

 

3. 두 좌표간의 거리

두 좌표간의 거리를 구하려면 두 좌표는 DMS표현 방식이어야 함..

도는 도, 분은 분, 초는 초끼리 연산을 한다.

  37° 33′ 58.97″ N , 126° 58′ 39.78″ E (서울시청)
- 37° 33′ 56.08″ N , 126° 58′ 41.10″ E (서울광장)

= 0 ° 0 ′ 2.89" , 0 ° 0 ′ -1.32"

//지리좌표간 두 점의 거리 계산을 위한 DMS연산
public HashMap<String, Double> DMSCalculationForDistance(Double targetDeg, Double targetMin, Double targetSec, Double opDeg, Double opMin, Double opSec)throws Exception{
    HashMap<String, Double> result = new HashMap<>();
    result.put("resultDeg",targetDeg-opDeg);
    result.put("resultMin",targetMin-opMin);
    result.put("resultSec",targetSec-opSec);

    return result;
}


//DMS 연산 결과로 거리 구하기
public Double getDistanceByDms(Double latDeg,Double latMin, Double latSec,Double lonDeg, Double lonMin, Double lonSec) throws Exception{
    Double result;
    result = Math.sqrt(Math.pow(latDeg*88.9036+latMin*1.4817+latSec*0.0246,2) + Math.pow(lonDeg*111.3194+lonMin*1.8553+lonSec*0.0309,2));
    return result;
}

 

4. 특정지점에서 특정 거리의 좌표 구하기

이 경우도 DMS 표현방식의 좌표로 계산하였다.

예를 들어   37° 33′ 58.97″  , 126° 58′ 39.78″ 좌표에서 서쪽으로 5km 떨어진 지점의 좌표를 구한다거나 하는 경우,

5km 만큼의 경도 수치를 구해서 빼준다.

동쪽으로 5km 떨어진 지점이라면  수치를 더해주고, 북쪽으로 5km 떨어진 지점이라면 5km만큼의 위도 수치를 더해준다.

위경도 1분, 1초 값은 아래 수치로 계산하였다.

  • 위도 1분 = 1.85km, 1초 = 30.8m
  • 경도 1분 = 1.48km, 1초 = 25m
 //위도 5km = 약 2분 42.2초(1분=1.85km, 1초=30.8m로 계산)
int latDistanceMin = 2;
Double latDistanceSec = 42.2D;

//경도 5km = 약 3분 22.4초(1분=1.48km, 1초=25m로 계산)
int lonDistanceMin = 3;
Double lonDistanceSec = 22.4D;
//DMS 표현 위경도에 특정 거리를 더하는 연산
public HashMap<String,Double> latlonCalDistance (Double targetDeg, Double targetMin, Double targetSec, Double opDeg, Double opMin, Double opSec,String operator) throws Exception{
    HashMap<String,Double> result = new HashMap<>();
    Double resultSec;
    Double resultMin;
    Double resultDeg;

    //더하기 연산
    if(operator =="+"){
      if(targetSec+opSec>=60){
        resultSec = targetSec+opSec-60;
        resultMin = targetMin+opMin+1;
        if(resultMin >=60){
          resultMin = resultMin -60;
          resultDeg = targetDeg + opDeg + 1;
        }else{
          resultDeg = targetDeg + opDeg;
        }
      }else{
        resultSec = targetSec+opSec;
        resultMin = targetMin+opMin;
        if(resultMin >=60){
          resultMin = resultMin -60;
          resultDeg = targetDeg + opDeg + 1;
        }else{
          resultDeg = targetDeg +opDeg;
        }
      }

    //빼기 연산
    }else{
      if(opSec > targetSec){
        resultSec = 60-opSec+targetSec;
        resultMin = targetMin-1;
        if(opMin > targetMin){
          resultMin = 60-opMin+resultMin;
          resultDeg = targetDeg -1 - opDeg;
        }else{
          resultMin = resultMin-opMin;
          resultDeg = targetDeg - opDeg;
        }
      }else{
        resultSec = targetSec - opSec;
        if(opMin > targetMin){
          resultMin = 60-opMin+targetMin;
          resultDeg = targetDeg -1 - opDeg;
        }else{
          resultMin = targetMin-opMin;
          resultDeg = targetDeg - opDeg;
        }
      }
    }
    result.put("resultDeg",resultDeg);
    result.put("resultMin",resultMin);
    result.put("resultSec",resultSec);
    return result;
}

 


참고 링크

 

 

위도 경도 계산법

위도 경도를 아래 공식에 대입해서 d(거리)값을 구한 상태 입니다. ==========점(x1, y1)과 직선(ax+by+c=0) 사이의 거리(d) 구하는 공식 ====================== d = |ax1 + by1 + c | / sqrt(a^2 + b^2) =======..

lovestudycom.tistory.com

 

 

지리좌표 거리 - 위키백과, 우리 모두의 백과사전

지리좌표 거리(Geographical distance)는 경위도좌표계를 기반으로 하는 좌표체계에서 얻어지는 두 지점의 좌표로 부터 측정되는 거리측량을 가리킨다. GPS로 부터 좌표값을 얻어 두 지점간의 지리좌

ko.wikipedia.org

 

반응형
반응형
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.springframework.stereotype.Component;

public class AES256 {
	//AES256은 256bit=32byte의 암호화 키가 필요함.
    private final String key = "1234567890123456789012"; 
    private final String iv = key.substring(0, 16); // 16byte의 초기화벡터값

//암호화메소드
    public String encrypt(String plainText) throws Exception {
    	//암호화 모드는 CBC를, 패딩은 PKCS5을 사용
        Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
        IvParameterSpec ivParamSpec = new IvParameterSpec(iv.getBytes());
        c.init(Cipher.ENCRYPT_MODE, keySpec, ivParamSpec);

        byte[] encrypted = c.doFinal(plainText.getBytes("UTF-8"));
        //base64로 인코딩
        return String(Base64.encodeBase64(encrypted));
    }

//복호화메소드
    public String decrypt(String cipherText) throws Exception {
        Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
        IvParameterSpec ivParamSpec = new IvParameterSpec(iv.getBytes());
        c.init(Cipher.DECRYPT_MODE, keySpec, ivParamSpec);

        byte[] decodedBytes = Base64.decodeBase64(cipherText);
        byte[] decrypted = c.doFinal(decodedBytes);
        return new String(decrypted, "UTF-8");
    }

}

 

* 패딩

암복호화 할 때 인풋이 암호 블럭 사이즈의 배수와 맞지 않는 경우 배수에 맞춰 빈공간을 채우는 것을 패딩이라고 함.

* IV

CBC모드에서 최초의 평문블록을 암호화 할 때 '한 단계 앞의 암호문블록' 역할을 할 비트열


패딩 참고

 

OKKY | PKCS#5 패딩과 PKCS#7 패딩의 차이점

암복호화 할 때 인풋이 암호 블럭 사이즈의 배수와 맞지 않으면 배수에 맞춰 빈공간을 채워주게 됩니다. 이 채워주는 방법을 패딩이라고 부르는데 여기서 PKCS#5와 PKCS#7의 차이를 설명하겠습니

okky.kr

 

반응형

+ Recent posts