반응형

이번엔 JSON형태로 데이터를 넘기고 받는 방법을 알아보겠습니다.

 

객체를 JSON처리하기 위해 GSON과 SIMPLE JSON 라이브러리의 힘을 빌렸습니다.

처음에 구성은 Simple Json만 사용하여 구성해봤지만, 단순 Array에 담은 데이터를 넘기는건 문제가 없지만 Vo객체를 JSONObject에 넣어서 넘기게되면 "key" 처리가 정상적으로 되지 않아 파싱부분에서 에러가 발생하는 것을 발견하였고, 넘기기전에는 Gson을 통해 JSON화하여 넘기도록 하였습니다.

 

JSON처리하여 소켓통신하기

Server

 

이번엔 Gson과 simple Json을 사용할 예정이므로 pom.xml에 아래 정보를 추가해야 합니다.

pom.xml

<!-- JSON SIMPLE -->
<dependency>
    <groupId>com.googlecode.json-simple</groupId>
    <artifactId>json-simple</artifactId>
    <version>1.1.1</version>
</dependency>

<!-- gson -->
<dependency>
	<groupId>com.google.code.gson</groupId>
	<artifactId>gson</artifactId>
	<version>2.8.5</version>
</dependency>

 

SokcetThreadServer.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.json.simple.JSONObject;

import com.google.gson.Gson;

public class SocketThreadServer extends Thread {
	
	private static final Logger logger = Logger.getLogger(SocketThreadServer.class);
	
	private Socket socket;
	public SocketThreadServer(Socket socket){
		this.socket=socket;
	}
	
	private static final InterlockDao interlockDao = InterlockDao.getIntstance();
	
	//JSON 데이터 넘기기
	public void run(){
		BufferedReader br = null;
		PrintWriter pw = null;
		
		try{
			String connIp = socket.getInetAddress().getHostAddress();
			System.out.println(connIp + "에서 연결 시도.");

			br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			pw = new PrintWriter(socket.getOutputStream());
			
			// 클라이언트에서 보낸 문자열 출력
			String returnMessage = br.readLine();
			System.out.println(returnMessage);
			
			Gson gson = new Gson();
			JSONObject jo = gson.fromJson(returnMessage, JSONObject.class);
			List<Map<Object, Object>> list = (ArrayList<Map<Object, Object>>) jo.get("list");
			
			for(int i=0; i<list.size(); i++) {
				System.out.println(list.get(i).toString());
			}
			// 클라이언트에 문자열 전송
			pw.println("수신되었다. 오버!");
			pw.flush();
			
			HashMap<String, Object> params = new HashMap<String, Object>();
			List<Map<String, Object>> test = interlockDao.selectTest(params);
			for(int i=0; i<test.size(); i++) {
				System.out.println(test.get(i));
			}
		}catch(IOException e){
			logger.error(e);
		}finally{
			try{
				if(pw != null) { pw.close();}
				if(br != null) { br.close();}
				if(socket != null){socket.close();}
			}catch(IOException e){
				logger.error(e);
			}
		}
	}
}

이번에도 마찬가지로 데이터를 먼저 받고 응답을 하는 서버 코드입니다.

작성하게될 클라이언트에서 JSONObject에 ArrayList<vo> 컬렉션을 "list" 키에 담아서 발송하는 코드를 작성 예정인데, 파싱하는 부분은 Map형태로 되어있습니다. JSON으로 파싱하면서 VO 객체를 단순 Map의 컬렉션처럼 key, value화 시켰기 때문입니다. 같은 VO로 파싱하려고 하면 파싱에러가 발생하는것을 볼 수 있습니다.

 

App.java

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import org.apache.log4j.Logger;

import kr.or.kisa.ktoaInterlock.socket.SocketThreadServer;

public class App {
	
	private static final Logger logger = Logger.getLogger(App.class);
	
	private static final int PORT_NUMBER = 4432;
	
	public static void main(String[] args) throws IOException{
		
		logger.info(":::                                                :::");
		logger.info(":::       Socket Application  Process Start        :::");
		logger.info(":::                                                :::");
		
		try(ServerSocket server = new ServerSocket(PORT_NUMBER)){
			while(true){
				Socket connection = server.accept();
				Thread task = new SocketThreadServer(connection);
				task.start();
			}
		}catch(IOException e){
			logger.error(e);
		}
	}
}

작성 후 소켓서버를 동작시킵니다.

 

Client

클라이언트 프로젝트도 별도로 빼셨다면 server 코드에서 추가한 pom.xml 정보를 입력하여 Gson과 simple Json을 추가해주세요.

 

Client3.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;

import org.json.simple.JSONObject;

import com.google.gson.Gson;

public class Client3 {
    private Socket socket;
    private BufferedReader br;
    private PrintWriter pw;
    
    public Client3(String ip, int port) {
		try {
			// 서버에 요청 보내기
			socket = new Socket(ip, port);
			System.out.println(socket.getInetAddress().getHostAddress() + " 연결됨");
			
			br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			pw = new PrintWriter(socket.getOutputStream());
			
			ArrayList<BoardVO> list = new ArrayList<>();
			for(int i=0; i<5; i++) {
				BoardVO vo = new BoardVO();
				vo.setTitle(i+"번째 제목입니다!");
				vo.setContent("1234567890_testtest String 문자열 테스트 컨텐츠츠츠");
				vo.setIdx(i);
				vo.setWriter("홍길동");
				list.add(vo);
			}
			
			JSONObject jo = new JSONObject();
			jo.put("list", list);
			
			//VO 메시지 발송
			pw.println(new Gson().toJson(jo));
			pw.flush();
			
			//발송 후 메시지 받기
			System.out.println(br.readLine());
		} catch (IOException e) {
		    System.out.println(e);
		} finally {
			// 소켓 닫기 (연결 끊기)
			try {
			    if(socket != null) { socket.close(); }
			    if(br != null) { br.close(); }
			    if(pw != null) { pw.close(); }
			} catch (IOException e) {
			    System.out.println(e);
			}
		}
    }
}

 

ArrayList<BoardVO> 형태의 컬렉션 리스트에 데이터를 담고 JSONObject 키값 list에 담은 후 Gson을 활용하여 JSON화한 문자열을 발송합니다.

 

App.java

public class App{
    public static void main( String[] args ) {
    	String ip = "서버의 IP";
        int port = 서버의 포트;
        new Client3(ip, port);
    }
}

작성이 완료되었으면, 서버를 동작시키고 클라이언트에서 JSON을 발송해본다.

 

 

동작결과

서버에 정상적으로 vo별로 담은 정보가 파싱되는것을 볼 수 있습니다.

 

클라이언트에서도 결과 문자열이 받아진것을 볼 수 있습니다.

 

 

주의사항

JSON파싱 로직시 GSON의 도움 없이 Simple JSON만으로 처리시 아래처럼 데이터가 들어오는것을 볼 수 있습니다.

JSONObject jo = new JSONObject();
jo.put("list", list);
pw.println(jo.toJSONString());

"idx":"0", "title":"0번째 제목입니다!" 인 JSON형태가 아니다.

 

꼭 Gson의 toJSON메소드를 활용하여 전체적으로 JSON형태가 될 수 있게 처리하여 발송하도록 해야 받는 곳에서 파싱하는 경우 문제가 없습니다.

JSONObject jo = new JSONObject();
jo.put("list", list);
pw.println(new Gson().toJson(jo));

 

반응형