설정 잘못했다가 경로 인식 못해서 회사에서 너무 민망했는데 (아무리 초보들꺼여도 우리플젝 욕먹음 당연 속상함) 이게 설정을 블로그 짜깁기로 보다보니 제대로 꼬여서 그런거였다. 스프링부트 버전이 높아서 인식이 안되나 별별 생각을 다 했는데 집에 와서 찬찬히 풀어보니까 되네 돼!!!!!!

 

 


 

 

1. 일단 jsp를 설정하며 마주친 에러.

jstl에 대한 dependency를 꽂았는데 나는 분명 처음에 에러가 안났다. 그래서 여기에 문제가 있는줄 몰랐는데 pom파일부터 차근차근 다시 저장하면서 갑자기 에러가 생겼다..? 문제가 있음 빨리빨리 말해라...!!!!!

 

Multiple markers at this line - Project build error: 'dependencies.dependency.version' for javax.servlet:jstl:jar is missing. - 'dependencies.dependency.version' for javax.servlet:jstl:jar is missing.

 

starter 는 중복이라 주석처리함

 

👉 에러창을 읽어보면 jstl:jar missing 그리고 version이 missing이라고 나온다.

각종 블로그글에는 embed-jasper와 jstl 세팅만 있고 jstl의 버전설정이 빠져있다. gpt도 마찬가지. 그냥 버전을 추가해주면 된다...하.... 🤦‍♀️🤦‍♀️🤦‍♀️

 

 


 

 

2. 타임리프가 경로를 못찾아요

application 세팅에서 jsp와 타임리프는 각각 따로 설정을 해주어야 한다. 그래서 yml서식에 맞게 잘! 들여쓰기로! 해줬는데! 자꾸 아래처럼 타임리프를 못찾는다고 나오는것....환장..... templates 폴더 하위에 thymeleaf폴더 잘 만들어줬는데 왜 못찾니 한참을 고민함.

 

Error resolving template [thymeleaf/index], template might not exist or might not be accessible by any of the configured Template Resolvers

 

회사에서 이거만 한시간을 검색하고 고민했을것임. 폴더를 통채로 붙여넣었어도 노트북이 새로 바뀌면서 설정이 뭔가 바꼈을수 있다...는 말씀을 듣고 그런가...싶어서 이거 할 마음이 뚝 사라졌었음. 

 

그리고 또다시 여러 글을 읽어보는데, 다른분의 설정파일에서 나랑 다른걸 발견했다. 하..설마..? 하고 추가했는데 맞았음.  

 

 

👉 나는 prefix에 /templates/만 써놓았어서 분명 해당폴더에 다 들어가있는데 한참 찾았더니 classpath:가 추가되어야 했다. 

 


 

그래서 결국 인덱스 화면 잘 뜹니다 ^^...

 

함정은 나는 관리자화면에서 연습하려고 했더니 거기까지 로그인하고 뭐하고 하는 여정이 너무 길다. 왜냐. 이제 디폴트가 jsp로 변경되었기때문에 (return "index"는 jsp를 찾아감) 기존의 타임리프 화면은 retun에다가 모두 타임리프를 붙여줘야 하기 때문이죠... (뷰 네임에 그렇게 세팅되어있으므로) 

 

이렇게 말입니다

 

 

이 많은 화면에 다 붙이는건 쓸데없는 노가다이므로 그냥 로그인없이 접근하는 화면 하나 만들어서 작업해야겠다.

으휴 ㅠㅠ 개똥멍청이 될뻔했는데 그래도 멍청이정도는 되겠지 이제. 못살아..............

 

 

 

 

인간은 원래 해본것만 하려하고 (쉬우니까) 안해본걸 어려워하지..... ㅠㅠ  이걸 이렇게 헤맬줄이야.

 

회사 노트북에 개인 프로젝트를 다시 구동시키게 됐는데 (DB는 도커 & DBeaver로!)

자바 깔고 STS 설치하고 maven이랑 톰캣깔고 어... path는 다 잘 잡혔는데 왜 에러밭이지 ㅠㅠ...하면서 보니까 Builder..는 롬복 기능인데 이런것도 다 일일히 .jar 파일을 받았었구나 하면서 기억을 더듬어가는 중.

boot가 다해줘요~로 마지막 기억이 남아서인지 하나하나 빌드업했던게 기억들이 안난다.

 

lombok 설치하고 maven 업데이트 하니까 에러창 싸아악 사라지는거보고 숨멎할뻔했던 정신이 돌아왔다.

생각해보면 환경구축도 1~2번밖에 안해본 셈이니 허둥지둥 할만하다고 스스로를 다독여본다.......😅

 


 

 

그리고 이제 도커에 올려둔 mariaDB와의 연결문제가 생겼음. 에러가 뜸 ^^!!!!

혹시나해서 원래 쓰던 팀서버와도 연결해봤는데 아주 잘~ 작동하는걸 봐서는 이건 DBeaver와의 연결문제임 코드문제가 아님 ^^....

 

 

Access denied for user 'root'@'172.17.0.1' (using password: YES)

 

[오류 해결] [Docker][MySQL] Access denied for user 'root'@'172.17.0.1' (using password: YES)

Docker에 Mysql을 설치하고 웹프로젝트 실행하였는데 접속 오류가 발생하였습니다. Cannot create PoolableConnectionFactory (Access denied for user 'root'@'172.17.0.1' (using password: YES) 그래서 해결을 하려고 찾아보니

csksoft.tistory.com

 

[Docker][MySQL]Access denied for user ‘’@’172.17.0.1'(using password: YES)

Problem: Using $ mysql or mysql-workbench or navicat15 or SQLPro for Mysql to connect to the docker-mysql of this machine, the…

medium.com

 

본격적으로 오류를 수정해보려던 찰나... 분명 url에서 localhost로만 바꿔주면 된다는 말을 들었는데 ... 라고 생각해서 password를 봤더니 mariadb만 다르게 설정되어있었다 ^^... 패스워드 바꿔주니까 잘 접속됐음. (이와중에 localhost:3306/DB이름? <-여기 매칭 안시켜줘서 자꾸 못찾는다고 함. 대소문자도 구별하더라...)

 

boot의 application-dev.yml파일에서 서버 접속을 설정할땐 
 url: jdbc:mariadb://localhost:3306/octapdb?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
이렇게 localhost로 두고, 도커에서 3306:3306 으로 컨테이너를 생성했으므로 내가 3306으로 접속 ▶ 해당 컨테이너 ▶ octapdb로 이동이 다이렉트로 이루어진다. 너무 신기했음. 당연히 컨테이너는 running 이어야 한다!

 

 


 

 

하지만 localhost:8081로 접속하면 아래와 같이 에러메세지가 뜨면서 프로젝트에 세팅해놨던 '접속불가페이지라 홈화면으로 이동합니다' 화면이 무한루프로 돌았다... 이때부터 권한문제라는 생각이 들었다. (내가 만들었던 화면인데 정말 얄미웠음.....)

 

SpringBoot 콘솔창에 뜨는 에러문구

 

 

일반 접속자(비회원)면 기본 인덱스 화면으로 들어갈 수 있게 해뒀는데 왜 권한에러가 뜨나...싶어서 에러문구를 살펴보는데 definer/invoker of view lack rights to use them 이 문구가 눈에 들어왔다.

 

뒤져보니 mysql은 view는 table과 다르게 또 권한 (조회할 유저 설정)설정이 필요한것 같았고, 인덱스 화면에서 해당 뷰 데이터에 접속하려는데 권한이 없음 → 데이터 접근 불가한 유저라 에러화면에서 무한루프로 돌고있다고 추측했다.

 

원래 DB를 확인해보니 view 쿼리문에 definer가 기본으로 들어가있었다

 

 

이걸 보고 view를 열어봤더니 세상에 Definer가 왜 저모양이죠..? 나는 분명 데이터를 그대로 import했는데.....

 

왜 섞여있니..?

 

나는 root ID로접속했으므로 중간중간 root@%로 설정된 view를 열어보면 데이터가 잘 보이지만, octap@%로 된 뷰들은 접속하면, (속성은 그대로 잘 들고왔는데) Data가 아래와 같이 invalid table or column or function or definer/invoker of lack rights to use them. 으로 나온다.... 그렇담 뭐다? Definer를 수정해줘야 할 것 같다!

뷰에서 데이터를 볼 수가없으니 화면에도 뿌릴수가 없다...

 

 

그리고 방법을 알려주는 티스토리를 발견. 뒤져보니 ALTER를 통해서 해당 내용을 수정할 수는 있는데, 문제는 as 뒤에 뷰 생성 쿼리를 그대로 다 붙여줘야 한다는 것... 이게 무슨 노가다인지...ㅠㅠ 말이 alter지 그냥 새로 만드는거나 다름없었다. 한번에 바꿀수 없나 싶었는데 이러나저러나 쿼리문이 붙는걸 보고 걍..그냥..다...수기로 돌렸다.....

 

 

mysql view definer 수정

A 서버에서 디비를 그대로 백업해서 B 서버로 옮겨 왔다.하필이면 재수없게 view가 있다.definer가 A 서버에서 쓰던 계정(test@localhost)이 등록되어 있었다.그래서 지금 B 서버에서 testtest@localhost 계정

zzins.tistory.com

 

 

중간에 안뜨는 뷰만 내비두고 다 바꿔줬더니 프로젝트가 정상작동한다!

 

 

설치부터 디비연결까지 총 4시간걸렸다.. 원래 다른 분께서 dump하라고 알려주셨는데 어쩌다보니 db만 그냥 export해서 import처리만 하게 됐음. (사실 dump의 개념을 잘 모르겠어서 일단 내가 할 수 있는 방법으로 진행한것도 있었다)

 

이제 자잘한 설정만 보완하고 마무리해야겠다. 덕분에 이번 연휴는 마음편히 쉴 수 있게 됐다!

좋은 추리시간이었다...😅  정말 공부할건 한가득이구나.

 

플젝할땐 내꺼하기 바빠서 다른사람 코드를 깊이 들여다보질 못했는데 (심지어 난 갖다쓸일도 없었음) 복기한다고 열어보다보니 흥미로운 부분들이 보인다. 

 

<select id="similarPersonalityFindAll" resultType="MissionView">
    select * from
    mission_view
    where
    end_date>=curdate()
    and personality_id = 1
    order by 
    rand() 
    limit 4
</select>

 

 

이 부분은 인덱스 화면에서 비회원을 대상으로 보여주기위해, 쿼리문을 세팅해둔 부분인데, 다른건 다 알겠지만 order by 구문이 이해가 안갔다.

 

limit 4라서 4개만 뽑겠다는건 알겠고, 자바의 랜덤함수처럼 rand()도 랜덤함수 같은데 order by rand() limit 4는 그럼 무작위로 정렬해서 4개만 뽑는다는건가..? 했더니 정답.

 

이렇게 조합해서 쓰는건가 했더니 무작위로 추출할때 'order by rand()' 가 하나의 구문으로 쓰인다고 한다.

실행할때마다 다른값을 반환하는것, 그리고 0~1사이 이기 때문에 SELECT FLOOR(RAND() * 100) + 1; 이런식으로 가공을 해주어야 1~100까지의 난수가 나온다는것도 자바의 랜덤객체 특성과 동일하다. 😁

아니... 이거때문에 전부터 꽤 오래 고민했는데 너무 허무하게 처리돼서 조금 당황스럽다.

(* 아직 여러가지 테스트를 해본건 아니라 나중에 오류 터질수 있음 주의)

 

이 문제의 포인트는, DB에 HTML이 들어갔다가 나오면 한줄 출력이 된다는데 있다...

 

textarea 박스에서 엔터키를 쳐서 작성했음에도 불구하고 다시 불러오면 이렇게 한줄로 나온다

 


 

인터넷을 찾아봤을때 대부분의 의견은 이랬다.

-- 일단 이 작업의 전제는 textarea에서 wrap:hard로 저장해야 한다는 것. 띄어쓰기와 개행을 그대로 입력해주는 속성이다. 만약 이 속성없이 그냥 저장하면 css에서 아무리 줄바꿈 해봤자 적용이 안됨!

 

코딩교육 티씨피스쿨

4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등

tcpschool.com

 

 

1. 컨트롤러에서 replace로 ('\r\n","<br>")로 교체해서 데이터베이스에 저장하기. 단 사용자 수정화면에선 다시 반대로 바꿔줘야한다. ▶ 이렇게 하면 화면에서는 타임리프로 th:utext를 통해 꺼내면 알아서 개행처리된다

(*데이터베이스에서 <br>태그를 껴서 문장을 넣어놓고 th:utext로 뽑아보면 바로 확인가능)

 

2. 넣을때도 <textrea>, 꺼낼때도 <textarea>를 쓴다 (*해보진 않았음!)

 

3. 자바스크립트+정규식을 쓴다

 

4. (내가 한 방법) 꺼낼때 css속성인 white-space를 활용한다

 

컨트롤러에서 어떻게 처리해야하나...고민하며 검색하던 중에, css에서 줄바꿈 처리 속성인 white-space를 가지고 적용하면 된다는 이야기를 우연히 보게됐고 , 아니 이게 줄바꿈 처리하는 속성은 맞긴 맞는데 저장할때부터 잘만 저장해주면 이거 하나로 해결되는게 정말일까? 싶어서 헐레벌떡 해봤다.

 

 

 

▼ 처음봤을땐 이해못해서 지나쳤다가 (왜냐면 css만 한번 적용했었는데 안되길래 걍 안되는줄 알았음) wrap:hard 로 속성 저장 가능한걸 보고 다시보니 그걸 그대로 꺼내면되는구나!!!! 하고 이해한 글

 

textarea로 입력 받은 글을 공백과 줄바꿈을 살려 출력하기

HTML에디터가 아닌 일반 textarea 로 입력 받은 글을 페이지에 출력해야 할 경우가 많이 있습니다. 출력시에는 보통 JSP 라면 형태로 출력합니다. 이 경우 html 태그들은 escape 되어서 태그가 화면에 그

offbyone.tistory.com

 

 

white-space - CSS: Cascading Style Sheets | MDN

CSS white-space 속성은 요소가 공백 문자를 처리하는 법을 지정합니다.

developer.mozilla.org

 

 

브랜치 파고 남의 코드 쳐들어가서(허락받음) 끼워넣기

style="white-space:pre;"

style="white-space:pre-line;"


//---------------
<a th:href="@{/member/feed/log(s=*{missionLogId})}" th:if="*{logContents!=null}">
    <p style="white-space:pre-line;" class="contents" th:text="*{logContents}">미션 로그 내용 출력</p>
</a>

 

👉 값을 불러오는 박스에만 해당되면 되기 때문에 html에서 직접 설정했다.

 

 

그리고 매 우 잘 됨!

조합해서 시도해볼 생각 안하고 그냥 컨트롤러에서 replace 썼으면 초가삼간 태울뻔했다. 근데 또 그렇게 하는 이유가 있을테니, 나중에 오류생기면 그렇게 바꿀수도 있겠지 ...😂 제발 생기지 말거라.

 

 

처음엔 pre로 설정했는데, 반응형 확인하느라 모바일을 봤더니, 폭이 축소되어도 한 문장이 길면 튀어나가있었다.

mdn보고 자동줄바꿈이 되는 pre-line으로 처리해줌.

 

테스트 성공하자마자 정신 똑디 차리고 textarea가 있는 html, js 랑 출력값인 모든 html, js에 꽂아넣었다! 

 


 

 

웹화면 아주 잘나오고요
모바일화면

 

👉 기존에 엔터키를 넣어서 작성했던 글도, 모바일 화면에서 아주 잘 출력되는걸 볼 수 있음!

 

👉  위 모바일 화면을 웹으로 바꾸면 스크롤이 생기게 해놨는데, 그 안에서 줄바꿈 매우 잘 됩니다 😉

 

 

숙원사업 같은 애였는데 드디어 해결해서 속시원하다. 피드가 뷰 of 뷰인데 이런거 하나 신경안썼단 소리 듣고싶지 않았음 ㅠ ㅠ

 

잘 배운김에 textarea속성도 한번 쭉 읽어보았다! 속성을 빨리알았더라면 고민하는 시간도 줄었을텐데 ..!

 

<textarea>: The Textarea element - HTML: HyperText Markup Language | MDN

The <textarea> HTML element represents a multi-line plain-text editing control, useful when you want to allow users to enter a sizeable amount of free-form text, for example a comment on a review or feedback form.

developer.mozilla.org

 

✅ 라이브러리 만드는 방법

1. 함수로 만들기

function showDialog(){

//대화상자 띄우는코드

}

 

function closdDialog(){

// 대화상자 닫는 코드

}

2. 캡슐을 사용해서 패킹하기

라이브러리, 모달 파일 생성
html에는 list.js가 들어가있다. <script type="module" src="/js/admin/menu/list.js" defer></script>

 

 

#️⃣ Shadow root

 

 

ShadowRoot - Web APIs | MDN

The ShadowRoot interface of the Shadow DOM API is the root node of a DOM subtree that is rendered separately from a document's main DOM tree.

developer.mozilla.org

 

👉 shadow dom - 문서에 없던 루트가 shadow root를 통해 생기게 된다. (모달이 있는것처럼 삽입해주기 위함)

 

 

👉 클래스가 DOM을 부모로 직접 둘 수 있게 되었다. (web component가 가능해짐)

 

 

👉 innerText나 innerHtml로 갈아낄 수는 있지만 문제가 있다. (innerText는 body 안에 있는 엘리먼트에 쓰는 것이므로 이렇게 넣게되면 다르게 나온다!)

 

 

문제점

  1. 스타일을 가져오긴했지만 br태그까지 다 들고가는 문제가 있음
  2. 기존 페이지에있는 동일한 이름의 클래스가 충돌날 수 있음

👉 shadow root를 쓰면 고립됨 == 전체에 영향을 주는게 아니라 해당 일부에만 영향을 줌

 

 


#️⃣ Constructable styleSheets

 

스타일시트를 추가하는 법

 

this.host로 해야함!!

1. 호스트 생성 2. 시트 생성 3. replaceSync 에 메서드 추가 (리턴값으로 css 설정값을 갖는다)

👉 shadow가 생성되지 않는 한 css는 아직 적용되지 않음.

👉 shadow root가 element를 가져야한다.

 

//기존의 모달 html
<section class="modal"> // --- 이부분에 클래스가 끼워지면서 모달(배경+박스)이 생성되고 show 클래스로 나타난다
    <div class="frame">
        <h1 class="title">${title}</h1>
            <div class="content">
                ${contents}
            </div>
        <div class="command">
            <button>확인</button>
            <button>취소</button>
        </div>	
    </div>
</section>

👉 section을 직접insert하게되면 div하위에 section이 들어가므로 shadowChild자체를 section으로 잡아주기 위해 section을 변수로 빼준다!

appendChild에 section이 아닌 createrRootElement 메서드를 만들어서 넣어준다
슈도속성이 생겼다!

 

👉 createRootElement를 통해서 슈도에 들어갈 HTML을 넣어준다

 

👉 생성되는 rootElement를 상단으로 빼주고, 전달해서 appendChild 하도록 코드를 수정한다

👉 그리고 show메서드가 실행될 때 classList가 추가됨으로써 해당 모달이 나온다

 

 

 

라이브러리 만들기가 생각보다 어렵다 😵😵‍💫

+ Recent posts