🚩오전에 할일
👍 미션해결
✌️ adapter pattern 알아보기
사용파일 :
applicationDesc.jsp
serverBrowser_bak.jsp, ContextResourceBrowsingServlet, MyWebResouceImpl, MyWebResource
serverBrowser.jsp,
adapter pattern 폴더..
<%@page import="java.util.stream.Collectors"%>
<%@page import="java.io.File"%>
<%@page import="java.util.List"%>
<%@ 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>
<jsp:include page="/includee/preScript.jsp"/>
<style type="text/css">
.folder{
background: red;
}
.file{
background: green;
}
</style>
</head>
<body>
<ul id="explorer">
<%
List<File> children = (List)request.getAttribute("children");
String liTags = children.stream()
.map(f->{
String clz = f.isDirectory()?"folder":"file";
return String.format("<li class='%s'>%s</li>", clz, f.getName());
}).collect(Collectors.joining("\n"));
out.println(liTags);
%>
</ul>
<script type="text/javascript">
$("#explorer").on("click", "li.folder", function(){
location.href="?base=/04";
});
</script>
<jsp:include page="/includee/postScript.jsp"/>
</body>
</html>
@WebServlet("/explorer/serverBrowsing")
public class ContextResourceBrowsingServlet extends HttpServlet{
private ServletContext application;
@Override
public void init() throws ServletException {
super.init();
application = getServletContext();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String base = req.getParameter("base");
String baseURL = Optional.ofNullable(base) // /서버사이드 최상위 절대경로, 논리주소
.orElse("/");
// String basePath = application.getRealPath(baseURL); //물리경로
// File root = new File(basePath);
List<File> children = application.getResourcePaths(baseURL)
.stream()
.map(lp->{
String pp = application.getRealPath(lp);
return new File(pp);
}).collect(Collectors.toList());
Collections.sort(children);
req.setAttribute("children", children);
String viewName = "/WEB-INF/view/explorer/serverBrowser.jsp";
req.getRequestDispatcher(viewName).forward(req, resp);
}
}
이 코드로 비동기 해보기 미션!
요청이 동기냐 비동기냐보다 클라이언트가 어떤 형태의 정보를 요구하냐가 중요하다.
요청 헤더의 Accept를 확인하고 html(ui가 필요하냐), json(데이터)를 필요하냐를 파악해야한다.
String accept = req.getHeader("Accept");
헤더정보를 가지고 온다.
if(accept.contains("json")) {
데이터가 필요해 -> 마샬링
}else {
ui가 필요해!
}
어떤데이터가 필요한지 파악하고 그에 대한 처리를 한다.
먼저 대상이 필요하니 businessLogicLayer 로 만든다. service 안만들어놔서 일단그냥 메서드로...!
private void businessLogicLayer(HttpServletRequest req) {
String base = req.getParameter("base");
String baseURL = Optional.ofNullable(base) // /서버사이드 최상위 절대경로, 논리주소
.orElse("/");
// String basePath = application.getRealPath(baseURL); //물리경로
// File root = new File(basePath);
List<File> children = application.getResourcePaths(baseURL)
.stream()
.map(lp->{
String pp = application.getRealPath(lp);
return new File(pp);
}).collect(Collectors.toList());
Collections.sort(children);
req.setAttribute("children", children);
}
jsp로 가보자
비동기 요청을 만들어보자.
url : 현재 폴더의 어디로 가기 때문에 보낼 주소 없다.
method: 기본이라 get이다.
data = 보낼 데이터가 없다.
$.ajax({
dataType : "json"
}).do
ajax에 보낼 정보가 json밖에 없다. 그렇다면
$.getJSON({
}).d
이렇게 바꿀 수 있다.
$.getJSON("", {
param:"test"
}).d
getJSON을 쓸때는 첫번째는 무조건 url이다. 우리는 현재 주소를 보내기 때문에 화이트스페이스하고,
다음 중괄호에서 파람으로 보낸다.
💊 파일 이름이 필요하다.
💊 파일인지 파악이 필요하다.
💊 파일을 누르면 파일경로가 가야하는데, 파일객체는 물리 경로를 갖고있다. url논리경로가 필요하다.
↓↓↓↓
인터페이스를 만들자.
package kr.or.ddit.explorer;
public interface MyWebResource {
public String getName();
public String getUrl();
public boolean isFolder();
public boolean isFile();
}
✨원래 가지고 있는 객체에 변화를 주고 싶다면? 상속을 받아서 확장시킬 방법을 생각해야한다.
: 개방폐쇄의 원칙✨
File을 상속받고 있는 구현체를
public class MyWebResouceImpl extends File implements MyWebResource {
public MyWebResouceImpl(String pathname) {
super(pathname);
}
@Override
public String getUrl() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isFolder() {
// TODO Auto-generated method stub
return false;
}
}
상속받은 File이 이미 getName과 isFile을 가지고 있어서 나머지 두개만 메서드로 나온다.
isFolder도 isDirectory로 했다면 자동으로 됐을 것이다.
하지만 folder로 했으니까 구현해야한다.
MyWebResource는 알맹이 없이 파일을 확장하고 있다. 파일을 생성자에서 받는다. => adaptee가 없으면 adapter는 소용이 없다. <= 아무리 돼지코 젠더가 있어도 전압다른 두 돼지코가 없으면 소용이 없다.
그런데 생각해보니 파일에서 사이즈와 물리경로는 필요없다.
그래서 생성자에서 리턴 받았던 것과 extends한것도 지워준다.
그리고나니 아까 안만들었던 getName과 isFile도 다시 상속받아야한다.
그런다음 전역변수로 선언하고
(lp를 직접 찍어보면)
System.out.println(lp);
로지컬패스의 모습. 폴더들은 /가 있다. 지워주자. 파일 명이 필요하니까.
int length = lp.length();
int lastIdx = lp.lastIndexOf("/");
if(lastIdx==(length-1)) {
this.url = lp.substring(0, lastIdx);
}else {
this.url = lp;
}
있으면 지우고 없으면 그대로 url생성.
List<MyWebResource> children = application.getResourcePaths(baseURL)
.stream()
.map(lp->{
System.out.println(lp);
String pp = application.getRealPath(lp);
return new MyWebResouceImpl(new File(pp), lp);
}).collect(Collectors.toList());
Collections.sort(children);
진짜 정보는 new File이 가지고 있다. 전형적인 addapter패턴..!
int num = 3;
new Integer(num) => wrapper class
진짜 정보는 num이 가지고 있다.
wrapper는 진짜 객체가 아니다. 진짜 데이터는 웹핑당하고 있는 파일이 가지고 있다.
파일이 가지고 있지않은 정보를 추가하는 용도로 mywebresourceimpl을 사용한 것이다.
다른 말로 adapter 패턴이라고 한다.
comparable구현체가 아닌 MyWebResource는 sort에서 오류가 난다.
sort가 필요해서 comparable이 가능해야하므로 인터페이스에서 설정한다.
public interface MyWebResource extends Comparable<MyWebResource>{
compare는 구현되는 모든 구현체에서 사용해야하기 때문에 하나하나의 구현체에서 만드는 것이 아니라 인터페이스에서 만들어야한다.. 인터페이스에서도 바디를 넣을 수 있도록 자바 1.8에서 변화되었다.
인터페이스의 메서드에 default를 추가하면 인터페이스의 모든 구현체는 이 메서들르 사용할 수 잇다.
이렇게 되면 sort오류 해결
@Override
default int compareTo(MyWebResource o) {
return getName().compareTo(o.getName());
}
구현체에서 file은 마샬링할 필요가 없음. jsonignore(마샬링 no!) ,transient(직렬화 no!) 시켜주자
@JsonIgnore
private transient File file;
⛑️오류발견!
파일 정보는 나오지 않는다. isFile과 전역변수로 선언한 file이 이름이 비슷해서 같이 \ignore되어버린것
adapte되어지고 있는 대상을 adaptee라고 부르니까 file이름을 adaptee로 바꿔주니 잘된다.
이제 jsp로 이동하여 만들어보자.
<script type="text/javascript">
$.getJSON("", {
param:"test"
}).done(function(resp, textStatus, jqXHR) {
let dataList = resp.children;
let liTags = [];
$.each(dataList, function(idx, file){
let li = $("<li>")
.addClass(file.folder?"folder":"file")
.html(file.name);
liTags.push(li);
});
explorer.append(liTags);
});
let explorer = $("#explorer").on("click", "li.folder", function(){
location.href="?base=/04";
});
</script>
페이지가 렌더링 되자마자 파일이 필요 그러니까 한번더 비동기 요청을 해야한다.
반복되는 코드가 보인다면? ==> 모듈화!!
그래서 모듈화 ㄱㄱ
자바스크립트 동적언어의 특성상 파라미터가 있을수도 없을수도 모두 가능
그래서 사용자는 있나없나 확인해야한다. 확인하는 과정이 매번 있다. 또 반복?
그런데 이번에는 ui플러그인 사용해보자!
❤️fancytree❤️
https://github.com/mar10/fancytree
GitHub - mar10/fancytree: JavaScript tree view / tree grid plugin with support for keyboard, inline editing, filtering, checkbox
JavaScript tree view / tree grid plugin with support for keyboard, inline editing, filtering, checkboxes, drag'n'drop, and lazy loading - GitHub - mar10/fancytree: JavaScript tree view / tr...
github.com
⛑️adapter pattern 사용하기
adapter 패턴에 대해 알아보자.
앞으로 많은 디자인 패턴을 만나보게 될 것이다. 그때마다 다이어그램을 잘보고 파악해보자. 나만의 강점을 만들어야한다!
📖fancytree 사용하면 바꿔야할 것!
응답데이터의 형태
1. [ ]로 시작하고 끝나라 : 객체로 만들어서 다루었는데 배열로 내보내야해.
2. title, key 프로퍼티가 필요 (-> MyWebResource인터페이스에서 만든 형식이 일치하지 않는다. -> 어뎁터 패턴을 사용하여 형을 맞춰줄 수 있는 다른 객체가 필요하다.)
1번먼저 해결해보자.
엥 얻어걸렸네 , 우리는 어쩌다보니 children이 있어서 첫번째 문제는 해결하여 트리구조는 나오긴 한것이다.
결과를 보니.... 아니다. 칠드런으로 했더니 전부다 stream() 해버려서 쓸 수 없는 형식으로 나와버렸다.
결국 칠드런을 list로 다시 고쳐줌...
request에 list이름으로 children을 담은 다음 jsp로 와서 형식을 맞춰주기로 했다.
2번문제 해결하기
serverBrowser.jsp FancytreeNode<T>, FileWrapper
fancytree가 요구하는 개체를 알아야한다. json으로 파싱해달라고 한다.
사이트에서 도큐먼트를 보면 각 properties가 무엇을 말하는지 어떻게 쓰는지 나와있다.
lazyLoad는 폴더일때 자식들이 더 있어서 더 열리는 것을 lazyLoad라고 한다.
FancytreeNode인터페이스를 제네릭 타입으로 생성한다. 여기에도 인터페이스지만 메서드를 만들 수 있다. 비교하여 정렬하는 메서드를 만들어보자.
public String getTitle();
public String getKey();
public boolean isFolder();
public boolean isLazy();
public T getData();
@Override
default int compareTo(FancytreeNode o) {
if(isFolder()^o.isFolder()) {
return isFolder()?-1:+1;
}else {
return getTitle().compareTo(o.getTitle());
}
}
폴더는 폴더끼리 정렬, 파일은 파일끼리 정렬하기 위해 베타 연산자를 사용한다.
베타연산자(^)는 두 대상이 같으면 false를 반환한다.
같으면? 같은 것끼리 정렬하고, 다르면? 다르면 정렬을 하되, 폴더일때 더 앞의 순위로 정렬되도록 -1을 반환해준다.
( 2하고 3을 오름 차순으로 정리하면 2가 더 적으니까 앞으로 간다. == 2-3은 음수가 나와서 음수를 아픙로. 그러니까음수를 반환. )
<script type="text/javascript">
$("#tree").fancytree({
source: {
url: location.href,
cache: false
},
lazyLoad: function(event, data){
var node = data.node;
// Load child nodes via Ajax GET /getTreeData?mode=children&parent=1234
data.result = {
url: location.href,
data: {base: node.getKeyPath()},
cache: false
};
},
postProcess: function(event, data) {
console.log(data);
data.result = data.response.list;
}
});
</script>
❤️ 기본객체 마저 알아보기...!
PAGECONTEXT : 현재 JSP 페이지의 모든 정보(나무지 기본객체 참조)를 가진 객체.
정말인지 알아보기 위해 객체의 비교 방법을 알아볼 것이다.
<%=request %> <%=pageContext.getRequest() %>
결과 >
org.apache.catalina.connector.RequestFacade@489bb351
org.apache.catalina.connector.RequestFacade@489bb351
같음. 근데 같은 객체인지 비교해보자. 주소를 봐야함.
<%=request==pageContext.getRequest() %> // 참조 주소 비교하는 연산자
<%=request.equals(pageContext.getRequest()) %> //행위 객체를 비교하는 이퀄스 객체
js는 변수 형태가 없기 때문에 타입, 상태, 값 모두 같은지 비교하려고 === 세개짜리 연산자를 쓴다.
둘다 true true 나옴.
request가 하는 것은 context도 다 할수있다.
<% pageContext.forward(relativeUrlPath); %>
포워드 방식 이동도 가능하다.
버퍼가 없다면?
a가 나가고 끝나서 b는 보낼 수 없어
forward를 만나면 톰캣은 버퍼에 있는 것을 지우고 b만 내보낼 수 있도록 준비한다.
클라이언트는 b의 존재를 모른다. 서버안에서 이동했기때문에
<%
pageContext.include("/04/standard.jsp");
request.getRequestDispatcher("/04/standard.jsp").include(request, response);
%>
include도 가능
>> pageContext, pre, standard, post 4개가 모두 실행된다.
모듈화할때는 하나의 jsp가 온전한 jsp 형태로 있는 것이 아니다. head title같은 태그들 중복
버퍼를 중간에 방출을 하고 인클루드하냐 방출 안하고 인클루드 하느냐에 따라 결과가 다르게 온다.
pageContext가 정확하게 위치를 알려주는 반면 request를 이용한 것은 include된 파일이 어디로 들어올지 예측할 수가 없다. 이를 커스텀 태그 한것. >> <jsp:include page="/includee/postScript.jsp"/>
'내가 보려고 정리하는 > Spring' 카테고리의 다른 글
웹 : adapterpattern : 0317(3) (0) | 2023.03.20 |
---|---|
웹 : scope : 0317(2) (0) | 2023.03.17 |
웹 : jsp 기본객체( application ), js 함수지향언어, this!! :0316 (0) | 2023.03.16 |
웹 : JSP 기본객체, buffer, scope 저장소 Session : 0315 (0) | 2023.03.15 |
웹 : exeption, 예외처리, custom Exception : 0314 보강 (0) | 2023.03.14 |