Project Code : 링크
총 단계는 14단계 까지 있었지만, 단계별 요구사항은 상세히 적지는 않습니다.
모든 요구 조건 사항이 처음부터 오픈된건 아니라, 실제 작업 순서에는 차이가 조금 있습니다.
//저장소 inMemory -> Json 파일 저장으로 변경 v2
public class MainV2 {
private static long index;
private static final String DELETE_PREFIX = "삭제?id=";
private static final String MODIFY_PREFIX = "수정?id=";
private static final String DB_ROOT = "db/wiseSaying/";
private static final String LAST_ID_PATH = "db/lastId.txt";
private static class WiseSaying {
private final Long id;
private final String content;
private final String author;
public WiseSaying(Long id, String content, String author) {
}
@Override
public String toString() {
}
public String toJson() {
}
public static WiseSaying toObject(String json)
}
public static void main(String[] args) throws IOException {
}
private static void registerWiseSaying(BufferedReader br) throws IOException {
}
private static void saveWiseSaying(WiseSaying saying) throws IOException {
}
private static void printAllWiseSaying() throws IOException {
}
private static List<WiseSaying> loadAllWiseSaying() throws IOException {
}
private static void deleteWiseSaying(Long id) throws IOException {
}
private static void modifyWiseSaying(Long id, BufferedReader br) throws IOException {
}
private static Long loadLastId() throws IOException {
}
private static void saveLastId() throws IOException {
}
}
}
controller
-> service
-> repository
순으로 요청의 흐름이 이뤄지게 하였습니다.사용자
에게 입력받은 요청을 처리하기 위해 서빙하고, 결과를 사용자
에게 전달하는 역할을 가정하였습니다.목록?keywordType=author&keyword=작자
like 검색을 때려야 했습니다.http
통신의 queryParams
처럼 느껴졌고, 처리할 방법을 생각하던 중, Servlet 처럼 받은 queryParams
을 Map에 정리하여 controller 에 전달하는 아이디어가 생각났습니다.public class ServletUtils {
//EX) 목록?keyword=작자&keywordType=author
//out = Map 형식, {key -> value} => {keyword -> 작자}, {keywordType -> author}
public static Map<String, String> extractRequestParams(String commandString) {
Map<String, String> requestParams = new HashMap<>();
try {
String subString = commandString.substring(commandString.indexOf('?') + 1);
return Arrays.stream(subString.split("&"))
.map(pair -> pair.split("="))
.filter(keyValue -> keyValue.length == 2)
.collect(Collectors.toMap(keyValue -> keyValue[0], keyValue -> keyValue[1]));
} catch (Exception e) {
return requestParams;
}
}
}
main
에서 사용하도록 하였습니다.=
를 기준으로 왼쪽을 key, 오른쪽을 value로 가정하여 map 에 넣도록 하였습니다.확장성
을 생각해서 모든 queryParams 형식으로 오는걸 RequestParms Map 으로 처리해서 옮겨주었습니다.public class ControllerUtils {
/**
* 입력받은 requestParams 로, Pageable 객체를 만들어 줍니다.
* Handling 내용
* "page"
* "size"
* @param requestParams
* @return
*/
public static Pageable createPageable(Map<String, String> requestParams) {
int page = Integer.parseInt(requestParams.getOrDefault(PAGE, DEFAULT_PAGE.toString()));
int size = Integer.parseInt(requestParams.getOrDefault(SIZE, DEFAULT_SIZE.toString()));
return new Pageable(page, size);
}
/**
* 입력받은 requestParams 로, Search 객체를 만들어 줍니다.
* Handling 내용
* "keywordType"
* "keyword"
*/
public static Search createSearch(Map<String, String> requestParams) {
if(!requestParams.containsKey(KEYWORD_TYPE) || !requestParams.containsKey(KEYWORD)) {
//둘중 하나라도 비어있다면, 정상적인 조회가 불가능.
//exception or 전체 검색 되도록 설정.
//현재는 전체 검색되도록 기능구현.
return Search.empty();
}
String keywordType = requestParams.get(KEYWORD_TYPE);
String keyword = requestParams.get(KEYWORD);
return new Search(keywordType, keyword);
}
}
IOException
을 자주 handling 해주어야 했고, 이에 따라서 서비스 코드에 try-catch 문으로 처리하는 과정이 많이 들어갔습니다. (코드에 예외처리가 너무 침범)exception handler
를 AOP 개념과 함께 도입하기로 하였습니다.public class GlobalExceptionHandlingProxy implements InvocationHandler {
private final Object target;
public GlobalExceptionHandlingProxy(Object target) {
this.target = target;
}
@SuppressWarnings("unchecked")
public static <T> T createProxy(T target,
Class<T> classType) {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
new Class<?>[]{classType},
new GlobalExceptionHandlingProxy(target)
);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
return method.invoke(this.target, args);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if(cause instanceof IOException) {
System.out.println("연결 중 오류가 발생하였습니다. message = " + cause.getMessage());
System.exit(1);
} else if(cause instanceof CustomException) {
System.out.println(cause.getMessage());
} else {
System.out.println("기타 오류가 발생하였습니다. message = " + cause.getMessage());
System.exit(1);
}
} catch (Exception e) {
e.getCause();
System.out.println("처리되지 않은 Exception 발생" + e.getMessage());
System.exit(1);
}
return null;
}
}
Controller
에 프록시를 적용해주었습니다.public static void main(String[] args) throws IOException {
~~~
WiseSayingController wiseSayingControllerProxy
= GlobalExceptionHandlingProxy.createProxy(wiseSayingController, WiseSayingController.class);
~~~
😆😆😆 많은 리뷰 감사합니다!!!!!