'''땅따먹기 게임을 하려고 합니다. 

땅따먹기 게임의 땅(land)은 총 N행 4열로 이루어져 있고, 

모든 칸에는 점수가 쓰여 있습니다. 1행부터 땅을 밟으며 한 행씩 내려올 때, 

각 행의 4칸 중 한 칸만 밟으면서 내려와야 합니다. 단, 땅따먹기 게임에는 한 행씩 내려올 때, 

같은 열을 연속해서 밟을 수 없는 특수 규칙이 있습니다.'''



지난번과 동일한 2레벨 문제이며 동적프로그래밍을 사용하면 된다고 해서 풀고 있다.
근데 여전히 어렵다.

다익스트라 알고리즘과 비슷하게 접근하면 될거 같은데...


# 땅따먹기 역시 동적 프로그래밍으로 풀었따.

내 힘으로 풀어서 너무 기분이 좋구나.. 좀 시행착오도 많긴했따.


문제는 이러하다


[[1,2,3,5],

[5,6,7,8],

[4,3,2,1]];


위와 같은 배열이 있을 때 열이 중복 안되게 하여 최대 값을 구하는 것이다.

이런 경우 5 + 7 + 4 = 16이 제일 큰 경우가 된다.


위에서 언급 했듯이 이는 다익스트라 알고리즘과 매우 유사하다.(최소냐 최대냐의 차이일뿐)

최대값을 비교하고 이를 업데이트 하는 동적프로그래밍 개념을 다시금 사용하였다.


처음에 이 문제를 접근하려 했을때는 동적프로그래밍을 염두 했음에도 불구하고 row, column을 제어하려고 노력하였다.

그리고 가장 잘못 생각했떤게, 한번에 max를 찾으려고 했다는 것이다.

무슨 의미냐면 1부터 시작할 경우, 6,7,8에 1을 더한 값을 구한 후 바로 3,2,1 에 이를 계산 하려고 했다.

모든 경우의 수를 다 생각을 해서 해야했기에 이는 최소 O(N^3) 의 시간 복잡도가 필요했을것이다


하지만 다익스트라를 보면

다익스트라는 한번에 마지막 노드까지 전진하지 않는다. 시작 노드에서 다음노드로, 또 해당노드의 값을 계산 하고 이를 업데이트 하고 넘어간다. 


그렇기에 이 문제에서도 1번으로 6,7,8을 계산 한 후, 2번으로 다시 계산하고 값을 비교하고 업데이트 하는 식으로 하면 된다.

로직은 다음과 같다.

1. 처음 시작은 0번 로우의 원소들이다.

2. 2번 로우의 원소들과 비교한다

- 여기서 비교는 1번)(오리지널 원소)와 2번)(시작 노드 + 오리지날 원소 값)을 비교해서 1번)이 작으면 그 값을 2번으로 바꿔준다.

- 비교해야하는 주체가 필요하므로 나는 복제 테이블을 하나 만들어서 오리지널 원소는 복제테이블에서 뽑아오고 업데이트는 다른 리스트를 해주었다.

3. 반복.



1번에서 시작하면

[[1,2,3,5],

[5,6,7,8],

   7,8,9 가 되고 모두 오리지널 보다 크므로 값이 바뀐다. 

[4,3,2,1]];


바뀐후

[[1,2,3,5],

[5,7,8,9],

[4,3,2,1]];


이제 2번에서 시작한다.

[[1,2,3,5],

[5,7,8,9],

7,   9, 10 2번 + 2번째 원소들의 합이 오리지널보다 더 크다. 업데이트 하자.

[4,3,2,1]];


바뀐후

[[1,2,3,5],

[7,7,9,10], 7은 2번과 같은 인덱스이므로 문제의 규칙에 따라서 적용되지 않았다.

[4,3,2,1]];


다음은 3번이다.

[[1,2,3,5],

[7,7,9,10],

8, 9,  , 11 역시 모두 큰 값이므로 업데이트 해준다

[4,3,2,1]];


이렇게 반복을 하면 된다.


코드 상에서 row를 움직이기 위해 변수를 하나 선정한후 while로 돌렸다.

이게 최선의 코드는 아니나 효율성에서도 큰 문제 없이 돌아갔다.







현재 로그인, 이미지 업로드, DB 저장 등이 모두 다 구동 된다.

이제 핵심은 메인 페이지에서 업로드한 이미지들을 가져오면 된다.


매우 쉽게 생각했다.

이미 DB에 경로가 저장 되어있으니 그거 그대로 가져오면 되는 것 아닌가.


그런데 안된다.

아오 지금 이것때문에 이틀이 날라가고 있다.


크게 두가지로 접근 중이다.

하나는 어차피 이미지가 로컬경로에 있으니 로컬경로로 접근하여 가져오자.


-> Not allowed resource... 크롬에서 보안 문제로 바로 접속이 불가하다고 한다.

이를 수정하기위해 context path를 수정중인데 그래도 안된다..


두번째는 버퍼 스트림으로 그대로 읽어 오는 것인데

이것또 안된다. 컨트롤러에서 버퍼로 가지고 와도 이걸 jsp에서 어떻게 뿌려줘야할지 모르겠다...


ㅠㅠ



# 질문한 결과 로컬로 접근하는 것은 잘못됬으며

버퍼이미지를 그대로 갖고와서 뿌려주면 된다고 한다.


갖고오는것은 쉬운데 jsp에서 어떠헥 뿌려야할지 모르겠따.



# img 태그를 보면 src는 주소값이다.. 

나는 ResponseEntity byte[]로 가져온 값을 jsp 내에서 재조립 하려고 하는데 이게 잘 안된다.


<c:forEach items="${fdata}" var="data" varStatus="cnt">

<h2> ${data.value}</h2>

<img src = "data:image/jpeg;base64,${data.value}" alt="..." width="200" height="200" />

<img src="data:image/jpg;base64,<c:out value='${data.value}'/>" />

<img src="data:image/jpg;base64,${data.value}">

<h2> hell</h2>

    </c:forEach>

이런 식으로 구성중인데 되지 않는다.

아무래도 src 내에 컨트롤러를 불러와야하나보다.


http://hellogk.tistory.com/129


여기에 나와있는 방법을 참고해야겠따..


src에 컨트롤러를 불러오게 된다면 현재 파일을 가져와서 byte로 구성하는 로직을 바꿔야한다.


근데 또 문제 하나가 없는 파일이 있는 경우가 있어서.. 

위에 로직은 20개를 가져오고 그중에서 있는 파일만 접근해서 byte로 구성하게 했는데..


이걸 다시 바꾸면 어떻게 접근해야할지 감이 안잡힌다.

그냥 열심히 파일관리를 해야겠다 라는 생각이 든다..



문자열 s에 나타나는 문자를 큰것부터 작은 순으로 정렬해 새로운 문자열을 리턴하는 함수, solution을 완성해주세요.
s는 영문 대소문자로만 구성되어 있으며, 대문자는 소문자보다 작은 것으로 간주합니다.


대문자는 뒤로, 소문자는 앞으로 정렬하라는 뜻이다.


별 생각없이 선택정렬 연습 겸으로 해서 코드를 구성 했다.


for(int i = 0; i < s.length() ; i++) {

max_num = i;

for(int j = i ; j < s.length() ; j++) {

if((int)lst[j] > (int)lst[max_num]) {

max_num = j;

}

}


너무 간단한 거라 딱히 리뷰할 것도 없긴하다.

한가지 계속 얼탓던 부분이 바로 저 max_num 부분...


선택정렬이 제대로 유지되려면 최고 값 인덱스를 찾아서 이를 바꿔주면서 진행이 되야 하는데

저 부분을 기존에 i로 그대로 쓰니 제멋대로 진행이 됬다.


이래서 역시 코드는 직접 쳐봐야 안다..

# 이 책은 코드로 배우는 스프링 웹 프로젝트를 기반으로 하고 있습니다.

강력추천하는 책 이오니 스프링을 배우실 분들은 꼭 사서 보시길 바랍니다.


1) 전에 빌더스 할때는 로그인 세션을 컨트롤 단에서 해결했다.

쿼리로 로그인 확인 - vo가 존재 할 경우 session에 값 부여...

당시에는 이렇게 하는게 최고로 생각했다.



문제는 이렇게 할 경우 세션여부를 view에서 일일히 확인해줘야 했다. 위에처럼.. nav 단에서 일일히 확인하는 식으로..



이번에는 인터셉터가 그 역할을 하는것으로 바꾸었다.




아래 친구가 컨트롤러 이다. DB에서 id, pwd로 vo 값을 가져온다. vo가 있어야 로그인이 되므로 null이면 종료시켜야한다.



아래 친구는 인터셉터이다. 위에 model로 건네 준 값을 통해서 session을 부여한다.(아직 작업중이라 뭔가 많다...)


인터셉터는 막 사용할 수 있지 않다. xml에다가 아래처럼 꼭 등록을 해줘야한다.

첫번째처럼 전체 경로에 따른 interceptor가 있을 수 있고 아니면 특정 경로에 맞추어서 가능하다.



근데 웃긴점은 잘못된 아이디 / 비밀번호의 경우도 세션이 넘어가진다는 점 ㅡ,.ㅡ;; res가 null로 나오는데도 불구하고 그렇게 작동되니 참으로 신기할 따름이다.


두번째로는 파일 업로드 이다.

나의 경우엔 이미지 게시판이 주 이므로 메인 페이지에서 modal창을 통해 파일 업로드를 하는 식으로 구성 하였다.

파일 업로드의 경우 신경써야할 것이 몇가지 있다.

1. DB 구성, 게시판 테이블, 파일 경로가 저장될 테이블을 잘 설정 해놔야 한다.

2. LAST_INSERT_ID(); : 1번의 연장선이다.


내가 파일을 업로드 한다면 DB에는 크게 2가지 작업이 진행된다. 하나는 게시글의 저장이고, 다른 하나는 파일경로의 저장이다.

즉 10번 게시글에 hoya.jpg 가 올라간다고 하면 이 두가지가 각각 나눠져서 진행이 된다. 그렇기에 파일경로가 저장되는 테이블의 경우

필수적으로 10번, 즉 게시물의 넘버링이 붙어야 한다.


빌더스 때는 이런 비슷한 상황을 트리거를 만들어서 해결 했으나 이번엔 LAST_INSERT_ID()를 통해 해결하였다.

(가장 최근이 insert된 auto_increment를 가져온다)



컨트롤러에서 mutipart로 값을 가져온다. 얘네는 util class에서 정제된다(경로생성이 됨)


그 다음에 서비스 단에서 create를 하고 난 다음에 addAttach를 해준다. 이때문에 위에 Transctional이 필요로 하다.

오늘 이 부분때문에 매우 오랫동안 헤맸다...


쿼리문과 실제 삽입이 된 결고



서비스 단에 트랜잭션을 걸기위에선 위에 bean을 꼭 등록 해줘야한다. 나같은 경우 책을 부분부분 보다 보니 설정이 곳곳이 비어 있어서

안되는 경우가 발생하였고 이걸 모른체 2시간을 해맸다. 


막상 적어보니 오늘 한거 엄청 없는거 같다...


원래 계획은 오늘 war빼서 도메인 등록하는 거였는데... 내일로 미뤄야겠다.






제품명 : 카미노 독서대


가격 : 2만원 후반

사용기간 : 1주

목적 : 아이패드 받침대용

총평 : 독서대에 목적에 맞게 책을 보기에는 좋다.

다만 나처럼 아이패드를 올려놓고 그 위에 뭔가를 쓰려 한다면 독서대가 춤추는 모습을 볼 수 있다.

그나마 가장 낮은 각도로 하면 그나마!! 덜 흔들리지만

좀만 높아지면 부들부들 거려서 불안하다.

'생활리뷰(아이패드 악세사리 등..)' 카테고리의 다른 글

아이패드 어플, Nebo  (1) 2018.07.28
분노의 리뷰 : LG HBS-S80  (0) 2018.06.18

이번 프로젝트는 이미지 게시판을 중점적으로 사용해보기 위함이다.


현재는 로그인, 파일 업로드 까지 완료 되었고 이 정도 시점에서 전 프로젝트와 조금씩 비교해보려 한다.

(현플젝 : 친구야 / 이전플젝: 빌더스)


1. web.xml


기본적으로 이번 프로젝트는 최초 생성부터 Spring legacy를 사용했기 때문에

세팅이나 폴더 구조등에 대해 따로 신경 쓸 필요가 없었다.

전 프로젝트는 아예 웹 프로젝트를 메이븐으로 컨버팅 하다보니 폴더구조도 많이 이상하다.


web.xml에서 가장 큰 차이는

<url-pattern>/</url-pattern> 부분이다.


이번 플젝은 RestFul하게 만드는게 목표이므로 기존처럼 .do 로 안했다. 

(실제 웹사이트 중 .do로 불려지는 곳 있는데-가끔- 그럴땐 반갑다)


2. servlet.xml


차이가 많이 난다.

빌더스에선 xml을 하나만 해놨다.(시큐리티 제외) 그렇다 보니 DB 연결 관련된 설정 모두 다 같이 모여있다.

반면에 친구야 에선 root와 servlet을 따로 구분 해놨다.

(빌더스는 root가 없다..)


3. User 컨트롤러

(좌 : 친구야 / 우 : 빌더스)



가장 큰 차이는 일단 logger의 사용.. 오른쪽만 하더라도 syso로 뽑는게 편했따.

물론 지금도 logger를 자유자재로 사용하지는 않고 단지 등록해서 쓰는 정도이지만.

빌더스 할 당시에는 로거 설정 자체를 만드는게 되게 힘들어서 나중에 겨우 하긴 했지만 만족스럽지는 못했다.


두번째로는 URI

이번엔 RestFul 하게 가기 위해 최대한 명사형태로, 간단하게 구성하려 노력중에 있다.

개발자가 제일 어려운 부분이 이름 짓는거라고 하는데 URI가 그러하다. 생각보다 명사, 복수형, 자원을 나타내는.. 식으로 만드는게 쉽지가 않다.


이번 프로젝트는 진행하면서 좀 헷갈리는 부분이 많이 있는데

그중 하나가 @Inject, @autowired다.


빌더스 할때는 무조건 @autowired를 썻다. 이번에는 @inject를 쓴다.

둘다 같은 역할이지만 인젝트는 자바 자체, auto는 스프링에서 제공하는 것이기 때문에

스프링에 종속적이지 않기 위해선 인젝트를 쓰라고 되어있다.


그런데 스프링에 종속적이지 않다는 것은 무슨 말일까

단순히 스프링 지원 말고 다른 프레임 워크에서도 사용가능하다 로 이해하면 될듯 하다.


stackoverflow를 찾아보니 역시나 비슷한 질문이 많다.

결론적으로 보자면 가장 큰 차이는 @required이다.


https://www.linkedin.com/pulse/difference-between-inject-vs-autowire-resource-pankaj-kumar

여기서 설명이 잘 되어있는데 @inject는 만일 프로퍼티가 없을경우 에러를 발생하지만 @autowired는 null로 인식하고 넘긴다고 한다.


One of the differences between @Autowired and @Inject is that @Inject does not have the required field so in case we fail to find a suitable object to injected it will fail while @Autowired can used required=false and allow null able field (only if required!).







/*

두 정수 a, b가 주어졌을 때 a와 b 사이에 속한 모든 정수의 합을 리턴하는 함수, 

solution을 완성하세요. 

예를 들어 a = 3, b = 5인 경우, 3 + 4 + 5 = 12이므로 12를 리턴합니다. */


알고리즘이나 기타 생각할 것도 따로 없고 그냥 풀면 된다

단순히 더하기만 하면 되기때문에 입력크기가 커도 큰 문제 없는듯.




딱 한가지 생각해봐야하는 건 두 수의 차에 따라서 누가 먼저 시작하느냐 그 정도 일뿐..



7장 정렬 연습문제..

# 이 책이 대학 교재로 쓰일 줄은 몰랐다.. 그래서 답지가 없었구나.

# 간단하거나 쉽게 풀수 있는 문제는 skip..


7.3 입력이 역으로 정렬되어있을때 동일 수행시간 정렬 알고리즘을 모두 고르시오.

- 입력이 역으로 정렬 = 큰수로 정렬되어있다 = 무조건 정렬을 한번은 해야한다

- 따라서 위의 경우엔 O(N^2)이므로 이 수행시간을 갖는 알고리즘을 찾으면 된다.


7.9 두개의 정렬 리스트를 하나로 합병하는 데 필요한 최소, 최대 횟수를 바르게 표현한 것은?

(단 리스트의 길이는 각각 M과 N이며 M>= N 이다)


- 최소의 경우엔 극단적인 경우를 생각한다

즉 N의 모든 원소가 M의 가장 첫번째(M에서 가장 작은 원소) 보다 작은 경우... 따라서 이 경우엔 N이다.

- 최대의 경우엔 당연히 모든 경우를 다 확인하는것 이므로 M+N이다. 단 이때!

M >=N인 상황에서 제일 마지막은 할 필요가 없으므로 -1을 해줘야 한다. 따라서 M+N-1이다.


7.14 안정한 정렬 알고리즘을 모아놓은 것을 고르시오.


- Stable 알고리즘을 검색하면 많이 나온다.

- 단 여기서 Selection sort가 왜 안정하지 않은지 다시한번 상기하려 한다.

Selection sort는 최소값을 정하고 n번 돌면서 더 작은 최소값을 찾은뒤 교체를 한다.


만약 4, 4, 5, 6, 2, 1, 0 의 리스트가 있다면

첫번째에 4를 min으로 하고 n회 돌고 난 뒤에 0과 교체 된다.

즉 0, 4, 5, 6, 2, 1, 4가 되는데 이때 두개의 4의 인덱스 순서가 바뀌게 된다.



7.22 입력크기가 클때 힙정렬이 캐시메모리를 비효적으로 사용하는 이유를 설명하시오.


- 메모리구조, 운영체계 등에 대한 깊은 이해가 없어서 100% 설명은 못하겠으나 이해한것을 바탕으로 한다.

- 캐시 메모리는 일종의 주소의 즐겨찾기, 미래의 쓸거 같은 주소를 더 가져오는 셈

- 그렇기에 주소들이 모여있어야 효율이 좋다(배열처럼)

- 힙정렬의 핵심은 root와 제일 마지막 node를 교환 한 후에 heap을 생성 하는 것

- 문제는 바로 root와 마지막 node가 바로 옆에 붙어 있는게 아니라는 것이다.

- 즉 입력 크기가 매우 크다면 root와 마지막 node는 매우 멀기 때문에 캐시 메모리를 비효율적으로 사용하게 된다.


그 외에 나머지 문제들은 전부 프로그램 작성이라... 이번 장에선 이정도만 기억하면 될듯 싶다.


1와 0로 채워진 표(board)가 있습니다. 표 1칸은 1 x 1 의 정사각형으로 이루어져 있습니다. 표에서 1로 이루어진 가장 큰 정사각형을 찾아 넓이를 return 하는 solution 함수를 완성해 주세요. (단, 정사각형이란 축에 평행한 정사각형을 말합니다.)



현재 도전중인 문제..

너무 많은 경우의 수가 있어서 쉽게 접근을 못하는중..

자괴감 느낀다.. 


# 너무 뻔하게 생각을 해서 그런가 안 풀린다.





1차 완성본.


기본 원리는 첫번째 row에서 1을 검색한다.

그리고 1이 연속되는지 확인 한 후 첫번째 인덱스(start), 끝나는 인덱스(end)를 확인 한다.

그리고 두번째 로우부터 이 인덱스 만큼 슬라이싱 된 리스트만을 확인한다.


이때 첫번째 로우에서 start-end+1 한 값, 즉 한변의 길이를 변수로 저장 한 후

두번째 row에서는 더 작은 값이 나오면 update 한다.(정사각형이므로)


lst = [[0,1,1,1],

       [1,1,1,1],

       [1,1,1,1],

       [0,0,1,0]];

lst2 = [[0,0,1,1],[1,1,1,1]];


위 두가지 경우에 한해서는 통과한다.



# 추가


이 문제가 어려운 이유는 무엇일까? 바로 안되는 경우가 발생 할 경우이다.

아마도, 이 문제를 처음 접하는 사람들은 거진 80-90%는 나 처럼 재귀적 형태로 접근 할 것이라 생각한다.


문제는 재귀적 접근을 하게 된다면 일단 매우 느리게 작동하고, 두번째로 안됫을 경우에 수습을 할라면 다시 처음부터 가야한다.

또한 이런식으로 문제를 풀라면 온갖 경우의 수를 다 생각한 다음 그 경우를 다 해결할 수 있는 코드를 짜야한다.

그렇기에 나온 방법이 동적 프로그래밍이다. 코드가 진행되면서 여태까지의 결과를 저장하는 식으로 간다. 

이렇게 짜게 된다면 굳이 다시 돌아갈 필요도 없고 안되는 경우를 따질 필요가 없다.


이러한 방식을 위에 문제에 적용한다면 이렇게 된다.

우선 최소한의 정사각형 사이즈는 몇일까? 2 * 2 , 즉 4이다.

그렇기에 2 * 2, 총 4칸을 보면 된다.


두번째로 4칸을 볼때 무엇을 봐야할까, 1의 갯수? 아니다. 0의 유무를 확인해야한다.


세번째, 그렇다면 이제 끝난것인가? 다음을 보자


1 1   0 1   0 0  0 0

1 1   1 1   1 0  0 0


위 네가지 경우 중 당연히 제일 왼쪽만이 2 * 2 정사각형이고 나머지는 아니다.

그런데 엄밀히 말하면 2번째, 세번째의 경우에는 아니라기 보단 1 * 1 의 정사각형이다.


그렇다면 다시 두번째로 돌아가서, 우리는 0의 유무를 확인해야만 하고 세번째에서 확인을 했는데 이것을 어떻게 기록해야 할까??

if, else if, else if로 다 돌려야 할까? 이렇게 가능하긴 할 텐데 코드도 복잡하고 암튼.. 그래 ㅎㅎ


포인터(현재 위치한 인덱스)를 제외한 나머지 3개의 최소값을 구하고 그 값에다가 +1 만 하면 된다.

이렇게 하면 굳이 0인지 아닌지도 구분할 필요도 없다(포인터는 구분해야한다 성능 향상을 위해)

위에서 첫번째는 2가 되고 이를 포인터에 기록한다!! (동적 프로그래밍에 핵심)

두번째는 1, 세번째도 1(엄밀히 말하면 패스), 네번째도 패스


# 여기서 포인터를 언급하고 넘어가자면 오른쪽 하단, 즉 (1,1) 위치에 있는 숫자를 포인터로 한다.

왜냐하면 앞서 언급했듯이 정사각형 최소 사이즈는 2*2 이므로 이를 리스트에서 확인하기 위해 굳이 0번째 로우부터 할 필요가 없기 때문이다.


0, 1, 1, 1 -> 이 줄부터 확인 할 필요없고

1, 1, 1, 1 -> 여기 이 줄부터 확인하면 된다. 그것도 저 빨간색부터!

0, 1, 1, 1


다시 원래대로 돌아와서... 최소값을 확인하고 거기에 무조건 1을 더해주면 된다.


1 1   0 1   0 0  0 0

2   1 1   1 0  0 

위에 얘들은 제일 왼쪽 애만 바뀌고 나머지는 안바뀐다.

그리고 이게 반복된다.

그럼 어느 순간 이런 애가 나타 날 것이다.


ex1)

2,2

2,1 -> 1은 포인터라 아직 동적 할당이 안된 상황


이 의미는 무엇일까 즉, 1로 둘러쌓여져 있던 애들이란 뜻이다.


1, 1 ,1

1, 2, 2

1, 2, 1 

ex1) 의 경우를 넓게 보면 바로 위에 처럼 된 상황인 것이다. 그렇기에 ex1)은 동적 할당으로 3이 된다. 포인터를 제외한 나머지 3개에서 최소값을 찾고 거기에 1을 더해주기 때문에.


마지막으로 위에 4*4 예시를 단계별로 표현하고 마무리 하겠다..


0, 1, 1, 1 

1, 1, 1, 1 -> 최소값이 0이라 +1 해도 어차피 1인 상황

0, 1, 1, 1


0, 1, 1, 1 

1, 1, 2, 1

0, 1, 1, 1


0, 1, 1, 1 

1, 1, 2, 2

0, 1, 1, 1


0, 1, 1, 1 

1, 1, 2, 2

0, 1, 2, 1


0, 1, 1, 1 

1, 1, 2, 2

0, 1, 2, 3



컨트롤러 테스트를 위해


mockMvc를 연습 하던 중 만났던 문제이다.


@WebAppConfiguration 

test 클래스 위에 작성 되야하는 위 어노테이션이 임포트가 안되고

mockMvc 역시 임포트가 안되는 불상사...


m2를 날리고 update를 다 해봐도 안붙길래 겸사겸사 오늘접어야겠다 라고 마음 먹었다.


마지막 확인을 위해 porm.xml을 확인 하였는데


스프링 버젼이 3.1.1로 되어있었다...

아마도 지난번 mybatis 연결 테스트를 하면서 바뀐것 같은데..

ㅠㅠ 두시간을 날렸따...



+ Recent posts