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 - 이기종 시스템 간 메시지 교환 시 사용되는 양쪽의 시스템이 모두 이해할 수 있는 공통 데이터 표현 방식
- xml 단점
제약 조건이 까다로움
표현하고자 하는 데이터에 비해 meta data가 많음 페이로드가 무겁다? - json
: 데이터의 경량화.
: 스키마가 없어서 원하는 형태가 아닌 잘못된 형태로 데이터가 넘어올 수도 있다.
- xml 단점
- 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);
}
}
~자바빈의 규약~
- 값을 가질 수 있는 property 정의
- property 캡슐화
- 일정한 절차에 따라 값을 변경할 수 있는 interface 메소드 제공. = getter/setter
- 상태를 비교할 수 있는 인터페이스 메소드 제공.: hashCode, equals 재정의 (Override) = (==, equals)
- 상태를 확인할 수 있는 인터페이스 메소드 제공: toString을 override
- 직렬화 가능.: Serializable =mark Interface임(여/부를 나타내는 인터페이스)
- 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