728x90
Cilent
1단계 - 서버에 요청하고 응답받는 코드를 캡슐화한다.
- `.request.RequestAgent` 클래스 정의
// 역할
// - 통신 프로토콜에 맞춰 서버에게 요청을 전달하고 응답을 받는 일을 한다.
//
public class RequestAgent implements AutoCloseable {
Socket socket;
PrintWriter out;
BufferedReader in;
String status;
String jsonData;
public RequestAgent(String ip, int port) throws Exception {
socket = new Socket(ip, port);
out = new PrintWriter(socket.getOutputStream());
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
public void request(String command, Object value) throws Exception {
// 서버쪽으로 데이터를 보낸다.
// - 서버에 명령어를 한 줄 보낸다.
out.println(command);
// - 객체를 JSON으로 변환하여 서버에 보낸다.
if (value != null) {
out.println(new Gson().toJson(value));
} else {
out.println(); // 보낼 객체가 없으면 빈 문자열을 보내 서버에게 알린다.
}
out.flush();
// 서버에서 응답을 받는다.
status = in.readLine();
jsonData = in.readLine();
}
public String getStatus() {
return status;
}
public <T> T getObject(Class<T> type) {
return new Gson().fromJson(jsonData, type);
}
@Override
public void close() {
try {out.close();} catch (Exception e) {}
try {in.close();} catch (Exception e) {}
try {socket.close();} catch (Exception e) {}
}
}
### 2단계 - 서버에 요청하는 기능을 RequestAgent로 대체한다.
- `.pms.ClientApp` 클래스 변경
public class ClientApp {
static RequestAgent requestAgent;
public static void main(String[] args) throws Exception {
System.out.println("[PMS 클라이언트]");
requestAgent = new RequestAgent("127.0.0.1", 8888);
while (true) {
String input = Prompt.inputString("명령> ");
if (input.equals("/board/add")) {
addBoard();
} else if (input.equals("/board/detail")) {
detailBoard();
} else {
requestAgent.request(input, null);
if (requestAgent.getStatus().equals("success")) {
String result = requestAgent.getObject(String.class);
System.out.println(">>> " + result);
} else {
System.out.println("명령 요청 실패!");
}
}
if (input.equalsIgnoreCase("quit")) {
break;
}
}
requestAgent.close();
Prompt.close();
}
private static void addBoard() throws Exception {
Board board = new Board();
board.setNo(1);
board.setTitle("제목1");
board.setContent("내용1");
board.setRegisteredDate(Date.valueOf("2021-1-1"));
Member m = new Member();
m.setNo(100);
m.setName("aaa");
m.setEmail("aaa@test.com");
board.setWriter(m);
// 서버에 요청하고,
requestAgent.request("/board/add", board);
// 서버가 보낸 결과를 확인한다.
if (requestAgent.getStatus().equals("success")) {
System.out.println("게시글 저장 성공!");
} else {
System.out.println("게시글 저장 실패!");
}
}
private static void detailBoard() throws Exception {
HashMap<String,Object> map = new HashMap<>();
map.put("no", 100);
// 서버에 요청하고,
requestAgent.request("/board/detail", map);
// 서버가 보낸 결과를 확인한다.
if (requestAgent.getStatus().equals("success")) {
Board board = requestAgent.getObject(Board.class);
System.out.println(board);
} else {
System.out.println("게시글 조회 실패!");
}
}
}
### 3단계 - 서버가 응답하는 메시지를 상수 필드로 전환한다.
- `.request.RequestAgent` 클래스 정의
- `.pms.ClientApp` 클래스 변경
// 역할
// - 통신 프로토콜에 맞춰 서버에게 요청을 전달하고 응답을 받는 일을 한다.
//
public class RequestAgent implements AutoCloseable {
public static final String SUCCESS = "success";
public static final String FAIL = "fail";
Socket socket;
PrintWriter out;
BufferedReader in;
String status;
String jsonData;
public RequestAgent(String ip, int port) throws Exception {
socket = new Socket(ip, port);
out = new PrintWriter(socket.getOutputStream());
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
public void request(String command, Object value) throws Exception {
// 서버쪽으로 데이터를 보낸다.
// - 서버에 명령어를 한 줄 보낸다.
out.println(command);
// - 객체를 JSON으로 변환하여 서버에 보낸다.
if (value != null) {
out.println(new Gson().toJson(value));
} else {
out.println(); // 보낼 객체가 없으면 빈 문자열을 보내 서버에게 알린다.
}
out.flush();
// 서버에서 응답을 받는다.
status = in.readLine();
jsonData = in.readLine();
}
public String getStatus() {
return status;
}
public <T> T getObject(Class<T> type) {
return new Gson().fromJson(jsonData, type);
}
@Override
public void close() {
try {out.close();} catch (Exception e) {}
try {in.close();} catch (Exception e) {}
try {socket.close();} catch (Exception e) {}
}
}
public class ClientApp {
static RequestAgent requestAgent;
public static void main(String[] args) throws Exception {
System.out.println("[PMS 클라이언트]");
requestAgent = new RequestAgent("127.0.0.1", 8888);
while (true) {
String input = Prompt.inputString("명령> ");
if (input.equals("/board/add")) {
addBoard();
} else if (input.equals("/board/detail")) {
detailBoard();
} else {
requestAgent.request(input, null);
if (requestAgent.getStatus().equals(RequestAgent.SUCCESS)) {
String result = requestAgent.getObject(String.class);
System.out.println(">>> " + result);
} else {
System.out.println("명령 요청 실패!");
}
}
if (input.equalsIgnoreCase("quit")) {
break;
}
}
requestAgent.close();
Prompt.close();
}
private static void addBoard() throws Exception {
Board board = new Board();
board.setNo(1);
board.setTitle("제목1");
board.setContent("내용1");
board.setRegisteredDate(Date.valueOf("2021-1-1"));
Member m = new Member();
m.setNo(100);
m.setName("aaa");
m.setEmail("aaa@test.com");
board.setWriter(m);
// 서버에 요청하고,
requestAgent.request("/board/insert", board);
// 서버가 보낸 결과를 확인한다.
if (requestAgent.getStatus().equals(RequestAgent.SUCCESS)) {
System.out.println("게시글 저장 성공!");
} else {
System.out.println("게시글 저장 실패!");
}
}
private static void detailBoard() throws Exception {
HashMap<String,Object> map = new HashMap<>();
map.put("no", "1");
// 서버에 요청하고,
requestAgent.request("/board/selectOne", map);
// 서버가 보낸 결과를 확인한다.
if (requestAgent.getStatus().equals(RequestAgent.SUCCESS)) {
Board board = requestAgent.getObject(Board.class);
System.out.println(board);
} else {
System.out.println("게시글 조회 실패!");
}
}
}
Server
1단계 - 클라이언트의 요청 정보를 다루고 응답을 다루는 코드를 캡슐화 한다.
- .server.RequestProcessor 클래스 정의
- 클라이언트의 요청 정보를 다루는 일을 한다.
// 역할
// - 클라이언트와 통신하는 일을 담당한다.
// - 클라이언트 요청이 들어오면 그 요청을 처리할 객체를 찾아 실행하는 일을 한다.
// - 클라이언트 요청 정보를 객체에 보관하고, 응답 기능을 수행할 객체를 만드는 일을 한다.
//
public class RequestProcessor implements AutoCloseable {
Socket socket;
PrintWriter out;
BufferedReader in;
BoardTable boardTable = new BoardTable();
public RequestProcessor(Socket socket) throws Exception {
this.socket = socket;
out = new PrintWriter(socket.getOutputStream());
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
@Override
public void close() {
try {out.close();} catch (Exception e) {}
try {in.close();} catch (Exception e) {}
try {socket.close();} catch (Exception e) {}
}
public void service() throws Exception {
while (true) {
String command = in.readLine();
if (command.equalsIgnoreCase("quit")) {
in.readLine(); // 클라이언트가 quit 명령을 보낼 때 이어지는 값으로 빈 문자열을 데이터로 보낸다.
out.println("success");
out.println("goodbye");
out.flush();
break;
} else if (command.startsWith("/board/")) {
Request request = new Request(command, in.readLine());
Response response = new Response();
boardTable.execute(request, response);
// Response 객체에 보관된 실행 결과를 클라이언트에게 보낸다.
out.println(response.status);
if (response.getValue() != null) {
out.println(new Gson().toJson(response.getValue()));
} else {
out.println();
}
out.flush();
} else {
in.readLine(); // 클라이언트가 보낸 문자열을 읽어서 버린다.
out.println("success");
out.println(command);
out.flush();
}
}
}
}
- .server.Request 클래스 정의
- 요청 명령을 조회하고 요청 데이터를 꺼내는 일을 한다.
// 역할
// - 클라이언트 보낸 명령과 JSON 데이터를 보관하는 일을 한다.
// - 클라이언트가 보낸 데이터를 특정 타입의 객체로 리턴하는 일을 한다.
//
public class Request {
String command;
String jsonData;
public Request(String command, String jsonData) {
this.command = command;
this.jsonData = jsonData;
}
public String getCommand() {
return command;
}
public <T> T getValue(Class<T> type) {
if (jsonData == null || jsonData.length() == 0) {
return null;
}
return new Gson().fromJson(jsonData, type);
}
}
- .server.Response 클래스 정의
- 클라이언트에게 응답할 데이터를 보관하는 일을 한다.
// 역할
// - 클라이언트에게 응답할 정보를 보관하는 일을 한다.
public class Response {
public static final String SUCCESS = "success";
public static final String FAIL = "fail";
String status;
Object value;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
2단계 - 게시글 데이터를 저장하고 꺼내는 코드를 캡슐화 한다.
- .pms.table.BoardTable 클래스 정의
// 역할
// - 게시글 데이터를 저장하고 조회하는 일을 한다.
//
public class BoardTable {
List<Board> list = new ArrayList<>();
public void execute(Request request, Response response) throws Exception {
switch (request.getCommand()) {
case "/board/insert": insert(request, response); break;
case "/board/selectOne": selectOne(request, response); break;
default:
response.setStatus(Response.FAIL);
response.setValue("해당 명령을 지원하지 않습니다.");
}
}
private void insert(Request request, Response response) throws Exception {
Board board = request.getValue(Board.class);
list.add(board);
response.setStatus(Response.SUCCESS);
}
@SuppressWarnings("unchecked")
private void selectOne(Request request, Response response) throws Exception {
Map<String,String> params = request.getValue(Map.class);
int no = Integer.parseInt(params.get("no"));
Board board = findByNo(no);
if (board != null) {
response.setStatus(Response.SUCCESS);
response.setValue(board);
} else {
response.setStatus(Response.FAIL);
response.setValue("해당 번호의 게시글이 없습니다.");
}
}
private Board findByNo(int no) {
for (Board b : list) {
if (b.getNo() == no) {
return b;
}
}
return null;
}
}
3단계 - BoardTable 클래스를 이용하여 클라이언트 요청을 처리한다.
- .pms.ServerApp 클래스 변경
public class ServerApp {
public static void main(String[] args) throws Exception {
System.out.println("[PMS 서버]");
System.out.println("서버 실행중");
ServerSocket serverSocket = new ServerSocket(8888);
Socket socket = serverSocket.accept();
System.out.println("클라이언트가 접속했음");
RequestProcessor requestProcessor = new RequestProcessor(socket);
requestProcessor.service();
requestProcessor.close();
System.out.println("서버 종료");
serverSocket.close();
}
}
'Project' 카테고리의 다른 글
DB 모델링 및 테이블 준비 (0) | 2021.10.19 |
---|---|
데이터 관리 서버 만들기 - 4) 프로토콜 정의 및 적용 (0) | 2021.10.03 |
데이터 관리 서버 만들기 - 3) 사용자가 입력한 명령처리 (0) | 2021.10.03 |
Java로 게시판 자동 번호 생성하기 (0) | 2021.09.20 |
비트 연산자로 권한 설정하기 (0) | 2021.09.14 |