22.09.06. 천방지축 어리둥절 빙글빙글 돌아가는 JSP

2022. 9. 6. 21:57카테고리 없음

Project가 Dynamic Web Project일 때 / Java Project일 때 Build Path 하는 방법이 다르다.

왼쪽의 Dynamic Web Project는 WEB-INF에 lib 폴더를 생성하고, 해당 폴더 안에 넣을 jar 파일들을 넣어주면  Web App Libraries에 들어가는데, Java Project일 때에는 프로젝트에 lib라는 폴더를 따로 만들고 jar파일들을 넣어준 뒤 jar파일을 오른쪽 클릭> Build Path> Add to Build Path를 눌러 추가해준다.

 

  • 데이터의 직렬화 (Serialization)
    : 전송이나 저장을 목적으로 객체의 상태를 Byte Array(Bit Stream)로 변환하는 과정
  • json/xml - 이기종 시스템 간 메시지 교환 시 사용되는 양쪽의 시스템이 모두 이해할 수 있는 공통 데이터 표현 방식
    1. xml 단점
       제약 조건이 까다로움
       표현하고자 하는 데이터에 비해 meta data가 많음 페이로드가 무겁다?
    2. json
      : 데이터의 경량화.
      : 스키마가 없어서 원하는 형태가 아닌 잘못된 형태로 데이터가 넘어올 수도 있다.
  • Marshalling/Unmarshalling
    • Marshalling: native data → JSON/XML
    • Unmarshalling: JSON/XML → native data
  • 데이터 전달 과정
    • native data --(Marshalling)--> json/xml --(Serialization)--> byte array --(Deserialization)--> json/xml --(Unmarshalling)-->native data
    • native data <--(Unmarshalling)-- json/xml <--(Deserialization)-- byte array <--(Serialization)-- json/xml <--(Marshalling)-- native data

직렬화, Marshalling 학습하기 위한 코드

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import kr.or.ddit.object.TestVO;

public class JSONMarshallingDesc {
	public static void main(String[] args) throws JsonProcessingException {
		TestVO vo = new TestVO();
		vo.setProp1("Value1");
		vo.setProp2("Value2");
//		serialize(vo);
//		deSerialize();
//		
//		String json = marshalling(vo);
//		TestVO vo2 = unMarshalling(json, TestVO.class);
//		
//		System.out.println(vo2);
		 
		transfer(vo);
	}
	
	private static void transfer(Object target) {
		String json = marshalling(target);
		serialize(json);
	}
	
	private static <T> T unMarshalling(String json, Class<T>javaType) {
		try {
			ObjectMapper mapper = new ObjectMapper();
			return mapper.readValue(json, javaType);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			throw new RuntimeException(e);
		}
		
	}
	
	private static String marshalling(Object target) {
		ObjectMapper mapper = new ObjectMapper();
		String json;
		try {
			json = mapper
							.writerWithDefaultPrettyPrinter()
							.writeValueAsString(target);
			System.out.println(json);
//		String json2="{\r\n"
//				+ "  \"prop1\" : \"Value1\",\r\n"
//				+ "  \"prop2\" : \"Value2\"\r\n"
//				+ "}";
			//TestVO vo2 = mapper.readValue(json2, TestVO.class);
			return json;
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
	
	
	private static void serialize(Object target) {
		File objFile = new File("d:/contents", "obj.dat");
		
		//ObjectOutputStream 객체를 직렬화할 수 있다.
		try(
			FileOutputStream fos = new FileOutputStream(objFile);
			ObjectOutputStream oos = new ObjectOutputStream(fos);
			){
			oos.writeObject(target);
			
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
	
	private static void deSerialize() {
		File objFile = new File("d:/contents", "obj.dat");
		try(
			FileInputStream fis = new FileInputStream(objFile);
			ObjectInputStream ois = new ObjectInputStream(fis);
		){
			Object obj = ois.readObject();
			System.out.println(obj);
		} catch (IOException | ClassNotFoundException e) {
			
			throw new RuntimeException(e);
		}
	}
	
}

 

package kr.or.ddit.object;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.beanutils.BeanUtils;

public class BeanUtilsTest{
	public static void main(String[] args) {
		Map<String, Object> map = new HashMap<>();
		map.put("prop1","VALUE1");
		map.put("prop2","VALUE2");
		
		TestVO vo= new TestVO();
		
		Class<? extends TestVO> clz=vo.getClass();
		Field [] fields = clz.getDeclaredFields();
		for(Field fld : fields) {
			String fldName = fld.getName();
			System.out.println(fldName);
			//private라는 접근자를 public으로 바꿔버림
			fld.setAccessible(true);
			try {
				fld.set(vo,map.get(fldName));
			} catch (IllegalArgumentException | IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println(vo);
		vo = new TestVO();
		for(Entry<String,Object> entry:map.entrySet()) {
			System.out.println(entry.getKey());
			String key = entry.getKey();
			Object value = entry.getValue();
			try {
				Field fld =clz.getDeclaredField(key);
//				vo.setProp1("VALUE1");
				//모든 프레임워크는 자바빈의 규약에 의해 짜여진다.
				String setterName = "set"+key.substring(0,1).toUpperCase()+key.substring(1);
				Method setter =  clz.getDeclaredMethod("setProp1", value.getClass());
				setter.invoke(vo, value);
			} catch (NoSuchFieldException | SecurityException | NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println(vo);
		try {
			BeanUtils.populate(vo, map);
		} catch (IllegalAccessException | InvocationTargetException e) {
			e.printStackTrace();
		}
		System.out.println(vo);
        }
	}

~자바빈의 규약~

  1. 값을 가질 수 있는 property 정의
  2. property 캡슐화
  3. 일정한 절차에 따라 값을 변경할 수 있는 interface 메소드 제공. = getter/setter
  4. 상태를 비교할 수 있는 인터페이스 메소드 제공.: hashCode, equals 재정의 (Override) = (==, equals)
  5. 상태를 확인할 수 있는 인터페이스 메소드 제공: toString을 override
  6. 직렬화 가능.: Serializable =mark Interface임(여/부를 나타내는 인터페이스)
  7. property 보호 설정.

~데이터 캡슐화~

  • 정해진 절차에 따라서만 정보에 접근하겠다.

* Integer은 null을 받을 수 있고 int는 불가.

* transient 데이터 직렬화에서 제외하겠다는 뜻.

 

CalculateVO 

import java.io.Serializable;

import kr.or.ddit.enumpkg.OperatorType;

public class CalculateVO implements Serializable{
	private int leftOp;
	private int rightOp;
	private OperatorType operator;
	public String getExpression() {
		return operator.getExpression(leftOp, rightOp);
	}
	
	public int getLeftOp() {
		return leftOp;
	}
	public void setLeftOp(int leftOp) {
		this.leftOp = leftOp;
	}
	public int getRightOp() {
		return rightOp;
	}
	public void setRightOp(int rightOp) {
		this.rightOp = rightOp;
	}
	public OperatorType getOperator() {
		return operator;
	}
	public void setOperator(OperatorType operator) {
		this.operator = operator;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + leftOp;
		result = prime * result + ((operator == null) ? 0 : operator.hashCode());
		result = prime * result + rightOp;
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		CalculateVO other = (CalculateVO) obj;
		if (leftOp != other.leftOp)
			return false;
		if (operator != other.operator)
			return false;
		if (rightOp != other.rightOp)
			return false;
		return true;
	}
	@Override
	public String toString() {
		return "CalculateVO [leftOp=" + leftOp + ", rightOp=" + rightOp + ", operator=" + operator + "]";
	}
	
	
}

enum으로 정의한 operatorType

public enum OperatorType {
	PLUS('+', new RealOperator() {
		@Override
		public int realOperate(int leftOp, int rightOp) {
			return leftOp+rightOp;
		};
	}),
	MINUS('-', new RealOperator() {
		@Override
		public int realOperate(int leftOp, int rightOp) {
			return leftOp-rightOp;
		};
	}),
	MULTIPLY('*', (leftOp, rightOp)->{return leftOp*rightOp;}),
	//한 줄만 리턴할 때는 생략 가능
	DIVIDE('/',  (leftOp, rightOp)-> leftOp/rightOp);
	//스프링에서 많이 쓴다고요...?
	private OperatorType(char sign,RealOperator operator) {
		this.sign=sign;
		this.operator = operator;
	}
	
	
	private char sign;
	private RealOperator operator;
	public char getSign() {
		return sign;
	}
	public int operate(int leftOp, int rightOp) {
		return operator.realOperate(leftOp, rightOp);
	}
	
	private static final String PATTERN = "%d %s %d = %d";
	
	public String getExpression(int leftOp, int rightOp) {
		return String.format(PATTERN, leftOp, sign, rightOp, operate(leftOp,rightOp));
	}
	
}

calculateForm.jsp

<%@page import="OperatorType"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<script type="text/javascript" src="<%=request.getContextPath() %>/resources/js/jquery-3.6.1.min.js"></script>
<body>
<!-- 이항 연산자로 4칙 연산 처리. -->
<form action="<%=request.getContextPath()%>/calculate" method="post" name="calForm">
	<input type="number" name="leftOp" />
	<select name="operator">
		<%
			for(OperatorType single: OperatorType.values()){%>
				<option value = '<%=single.name()%>'><%=single.getSign()%></option>
			<%}
		%>
	</select>
	<input type="number" name="rightOp" />
	<input type="submit" value="=">
</form>

<script>
	let calForm =$(document.calForm).on("submit", function(event){
		event.preventDefault();
		
		let url = this.action;
		let method = this.method;
		//let data = $(this).serialize(); //QueryString
		let jsObj =	{
				leftOp:23,
				rightOp:34,
				operator: "PLUS"
				};
		let json = JSON.stringify(jsObj);
		
		
		$.ajax({
			url:url,
			method:method,
			contentType:"application/json; charset=utf-8",
			data: json,
			dataType:"json",
			success:function(resp){
				console.log(resp);
				calForm.after(resp.expression);
			},
			error: function(errorResp){
				console.log(errorResp.status);
			}
		});
		return false;
	});
</script>
</body>
</html>

CalculateServlet.java

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.fasterxml.jackson.databind.ObjectMapper;

import kr.or.ddit.enumpkg.OperatorType;
import kr.or.ddit.vo.CalculateVO;

@WebServlet("/calculate")
public class CalculateServlet extends HttpServlet{
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.setContentType("application/json;charset=utf-8");
		try(
				InputStream is = req.getInputStream();
				PrintWriter out =  resp.getWriter();
		){
			ObjectMapper mapper = new ObjectMapper();
			CalculateVO vo = mapper.readValue(is, CalculateVO.class);
			
			mapper.writeValue(out, vo);
			
		}
		
		
	}
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String left = req.getParameter("leftOp");
		String right = req.getParameter("rightOp");
		String opParam = req.getParameter("operator");
		
		int statusCode = HttpServletResponse.SC_OK;
		OperatorType operatorType=null;
		try {
			operatorType =  OperatorType.valueOf(opParam);
		}catch (Exception e) {
			statusCode=HttpServletResponse.SC_BAD_REQUEST;
		}
		
		
		
		if((left==null)||left.isEmpty()||!left.matches("\\d+")||(right==null)||right.isEmpty()||!right.matches("\\d+")) {
			statusCode=HttpServletResponse.SC_BAD_REQUEST;
		}
		if(statusCode==HttpServletResponse.SC_OK) {
			int leftOp = Integer.parseInt(left);
			int rightOp = Integer.parseInt(right);
			String expression = operatorType.getExpression(leftOp, rightOp);
			
			try(
				PrintWriter   out = resp.getWriter();
				){
				out.println(expression);
			}
			
		}else {
			resp.sendError(statusCode);
		}
		
		
	}
}

메소드...

//함수와 객체가 동일성을 갖는다
@FunctionalInterface
public interface RealOperator {
	public int realOperate(int leftOp, int rightOp);
	
	
}

 

 

 

alt+enter