CSS
vs code 에서 code snippet 등록하는 방법






쉽게 snippet 작성 하는 방법
snippet qenerator
<!-- container 를 만들고 -->
<div class="container">
<!-- 폭을 100% 모두 사용하고 싶다면 그냥 여기에 작성하면 된다 -->
<h1>제목</h1>
<p>p1 입니다</p>
<!-- 폭을 50%씩 사용하고 싶다면 -->
<div class="row"> <!-- 행을 만들고 -->
<div class="col"> <!-- 칼럼을 두 개 만들면 50%씩 폭을 사용할 수 있다-->
<h2>제목2</h2>
<p>content2</p>
</div>
<div class="col">
<h2>제목3</h2>
<p>content3</p>
</div>
</div>
</div>

<div class="row">
<div class="col-6">
<h3>나의 이미지1</h3>
<img class="img-fluid" src="images/top01.jpg">
</div>
<div class="col">
<h3>나의 이미지2</h3>
<img class="img-fluid" src="images/top02.jpg">
</div>
<div class="col">
<h3>나의 이미지3</h3>
<img class="img-fluid" src="images/top03.jpg">
</div>
</div>

JAVA & JSP
num 칼럼에서 1칸 뒤쳐진 (LAG) 값을
SELECT 하고 만일 값이 없으면 (NULL)
↱ 기본값을 0 를 부여하겠다는 의미 ↱ 칼럼의 별칭
SELECT num, writer, title, LAG(num, 1, 0) OVER (ORDER BY num DESC) AS prevNum
defualt 값 ↲ ↳ num에 대해서 내림차순 정렬한 결과에 대해서'
LEAD(num, 1, 0) OVER (ORDER BY num DESC) AS nextNum
FROM board ↳ LEAD 함수는 LAG 함수의 반대 개념
ORDER BY num DESC;
SELECT *
FROM
(SELECT num, writer, title,
LAG(num, 1, 0) OVER (ORDER BY num DESC) AS prevNum,
LEAD(num, 1, 0) OVER (ORDER BY num DESC) AS nextNum
FROM board
ORDER BY num DESC)
WHERE num=19
// 이전글, 다음글 처리를 위한 필드
private int prevNum;
private int nextNum;
public int getPrevNum() {
return prevNum;
}
public void setPrevNum(int prevNum) {
this.prevNum = prevNum;
}
public int getNextNum() {
return nextNum;
}
public void setNextNum(int nextNum) {
this.nextNum = nextNum;
}
getByNum 메소드 수정String sql = """
SELECT *
FROM
(SELECT b.num, writer, title, content, viewCount,
TO_CHAR(b.createdAt, 'YY"년" MM"월" DD"일" HH24:MI') AS createdAt,
profileImage,
LAG(b.num, 1, 0) OVER (ORDER BY b.num DESC) AS prevNum,
LEAD(b.num, 1, 0) OVER (ORDER BY b.num DESC) AS nextNum
FROM board b
INNER JOIN users u ON b.writer = u.userName)
WHERE num = ?
""";
dto.setPrevNum(rs.getInt("prevNum"));
dto.setNextNum(rs.getInt("nextNum"));
<div class="btn-group mb-2">
<a class="btn btn-outline-secondary bg-primary-subtle btn-sm
<%=dto.getPrevNum() == 0? "disabled" : "" %>" href="view.jsp?num=<%=dto.getPrevNum()%>">
<i class="bi bi-arrow-left"></i>
Prev
</a>
<a class="btn btn-outline-secondary bg-primary-subtle btn-sm
<%=dto.getNextNum() == 0? "disabled" : "" %>" href="view.jsp?num=<%=dto.getNextNum()%>">
Next
<i class="bi bi-arrow-right"></i>
</a>
</div>
<!-- Toast UI Editor CSS -->
<link rel="stylesheet" href="https://uicdn.toast.com/editor/latest/toastui-editor.min.css" />
<!-- Toast UI Editor JS -->
<script src="https://uicdn.toast.com/editor/latest/toastui-editor-all.min.js"></script>
<!-- 한국어 번역 파일 추가 -->
<script src="https://uicdn.toast.com/editor/latest/i18n/ko-kr.js"></script>
➜ toast ui 에 관련 css, javascript 를 로딩
<div class="container">
<h1>게시글 작성 양식</h1>
<form action="save.jsp" method="post" id="saveForm">
<div class="mb-2">
<label class="form-label" for="title">제목</label>
<input class="form-control" type="text" name="title" id="title" />
</div>
<div class="mb-2">
<label class="form-label" for="editor">내용</label>
<!-- Editor ui 이 출력할 div -->
<div id="editor"></div>
<textarea class="form-control" name="content" id="hiddenContent" ></textarea>
</div>
<button class="btn btn-sm bg-primary-subtle text-white btn-sm" type="submit">작성하기</button>
</form>
</div>
<script>
// 위에 toast ui javascript 가 로딩되어 있으면 toastui.Editor 클래스를 사용할 수 있다
// 해당 클래스를 이용해서 객체 생성하면서 {} object 로 ui 에 관련된 옵션을 잘 전달하면
// 우리가 원하는 모양의 텍스트 편집기를 만들 수 있다
const editor = new toastui.Editor({
el:document.querySelector('#editor'),
height:'500px',
initialEditType:'wysiwyg',
previewStyle:'vertical',
language:'ko'
});
document.querySelector("#saveForm").addEventListener("submit", (e)=>{
// 에디터로 작성된 문자열 읽어오기
const content = editor.getHTML();
// 테스트로 콘솔에 출력하기
console.log(content);
// 에디터로 작성된 문자열을 폼 전송이 될 수 있도록 textarea 의 value 로 넣어준다
document.querySelector("#hiddenContent").value = content;
// 테스트 하기 위해 폼 전송 막기
// e.preventDefault();
});
</script>
<div class="card-body p-1">
<%=dto.getContent()%>
</div>
<!-- Toast UI Editor CSS -->
<link rel="stylesheet" href="https://uicdn.toast.com/editor/latest/toastui-editor.min.css" />
<!-- Toast UI Editor JS -->
<script src="https://uicdn.toast.com/editor/latest/toastui-editor-all.min.js"></script>
<!-- 한국어 번역 파일 추가 -->
<script src="https://uicdn.toast.com/editor/latest/i18n/ko-kr.js"></script>
<h1>글 수정 페이지</h1>
<form action="update.jsp" method="post" id="editForm">
<div>
<label class="form-label" for="num">글번호</label>
<input class="form-control" type="text" name="num" id="num"
value="<%=dto.getNum() %>" readonly/>
</div>
<div>
<label class="form-label" for="writer">작성자</label>
<input type="text" class="form-control" name="writer" id="writer"
value="<%=dto.getWriter()%>" readonly/>
</div>
<div>
<label class="form-label" for="title">제목</label>
<input type="text" class="form-control" name="title" id="title"
value="<%=dto.getTitle()%>"/>
</div>
<div>
<label class="form-label" for="editor">내용</label>
<div id="editor"></div>
<textarea class="form-control" name="content"
id="hiddenContent"></textarea>
</div>
<button class="btn btn-success btn-sm">수정</button>
<button class="btn btn-danger btn-sm">Reset</button>
</form>
<script>
// 위에 toast ui javascript 가 로딩되어 있으면 toastui.Editor 클래스를 사용할 수 있다
// 해당 클래스를 이용해서 객체 생성하면서 {} object 로 ui 에 관련된 옵션을 잘 전달하면
// 우리가 원하는 모양의 텍스트 편집기를 만들 수 있다
const editor = new toastui.Editor({
el:document.querySelector('#editor'),
height:'500px',
initialEditType:'wysiwyg',
previewStyle:'vertical',
language:'ko',
initialValue:`<%=dto.getContent()%>`
});
document.querySelector("#editForm").addEventListener("submit", (e)=>{
// 에디터로 작성된 문자열 읽어오기
const content = editor.getHTML();
// 테스트로 콘솔에 출력하기
console.log(content);
// 에디터로 작성된 문자열을 폼 전송이 될 수 있도록 textarea 의 value 로 넣어준다
document.querySelector("#hiddenContent").value = content;
// 테스트 하기 위해 폼 전송 막기
// e.preventDefault();
});
</script>
<!-- 행을 만들고 -->
<div class="row my-3">
<!-- 4/12 인 칼럼을 만들고 margin-start:auto 를 부여해서 왼쪽 마진을 자동 부여한다 -->
<div class="col-lg-4 col-md-6 ms-auto">
<form action="list.jsp" method="get">
<div class="input-group">
<input type="text" name="keyword" class="form-control" placeholder="검색어 입력"/>
<button type="submit" class="btn btn-outline-secondary bg-primary-subtle btn-sm"><i class="bi bi-search"></i></button>
</div>
</form>
</div>
</div>
getCountByKeyword 메소드 추가// 전체 글의 갯수를 리턴하는 메소드
public int getCount(String keyword) {
int count = 0;
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = new DbcpBean().getConn();
// 글의 전체 갯수를 ROWNUM 중에서 가장 큰 값
String sql = """
SELECT MAX(ROWNUM) AS count
FROM board
WHERE title LIKE '%' || ? || '%' OR content LIKE '%' || ? || '%'
""";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, keyword);
pstmt.setString(2, keyword);
rs = pstmt.executeQuery();
if (rs.next()) {
count = rs.getInt("count");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null)
rs.close();
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
} catch (Exception e) {
}
}
return count;
}
// 검색 키워드를 담기 위한 필드
private String keyword;
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
selectPageByKeyword 메소드 추가// 특정 page 와 keyword 에 해당하는 row 만 select 해서 리턴하는 메소드
public List<BoardDto> selectPageByKeyword(BoardDto dto){
List<BoardDto> list=new ArrayList<>();
//필요한 객체를 담을 지역변수를 미리 만든다
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = new DbcpBean().getConn();
//실행할 sql문
String sql = """
SELECT *
FROM
(SELECT result1.*, ROWNUM AS rnum
FROM
(SELECT num, writer, title, viewCount, createdAt
FROM board
WHERE title LIKE '%' || ? || '%' OR content LIKE '%' || ? || '%'
ORDER BY num DESC) result1)
WHERE rnum BETWEEN ? AND ?
""";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, dto.getKeyword());
pstmt.setString(2, dto.getKeyword());
pstmt.setInt(3, dto.getStartRowNum());
pstmt.setInt(4, dto.getEndRowNum());
rs = pstmt.executeQuery();
while (rs.next()) {
BoardDto dto2=new BoardDto();
dto2.setNum(rs.getInt("num"));
dto2.setWriter(rs.getString("writer"));
dto2.setTitle(rs.getString("title"));
dto2.setViewCount(rs.getInt("viewCount"));
dto2.setCreatedAt(rs.getString("createdAt"));
list.add(dto2);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null)
rs.close();
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
} catch (Exception e) {
}
}
return list;
}
<%@page import="org.apache.tomcat.jakartaee.commons.lang3.StringUtils"%>
<%
// 검색 keyword 가 있는지 읽어와 온다
String keyword = request.getParameter("keyword");
// System.out.println(keyword);
if(keyword == null){
keyword = "";
}
//전체 글의 갯수
int totalRow = 0;
// 만일 전달된 keyword 가 없다면
if(StringUtils.isEmpty(keyword)){
totalRow = BoardDao.getInstance().getCount();
} else{ // 있다면
totalRow = BoardDao.getInstance().getCountByKeyword(keyword);
}
// 글 목록
List<BoardDto> list = null;
// 만일 keyword 가 없다면
if(StringUtils.isEmpty(keyword)){
list = BoardDao.getInstance().selectPage(dto);
} else{ // 있다면
// dto 에 keyword 를 담고
dto.setKeyword(keyword);
// 키워드에 해당하는 글 목록을 얻어낸다
list = BoardDao.getInstance().selectPageByKeyword(dto);
}
%>
⭐ StringUitls 클래스의 isEmpty() static 메소드를 이용하면
문자열이 비었는지 여부를 알 수 있다
null 또는 "" 빈 문자열은 비었다고 판정된다
StringUtils.isEmpty(keyword) 는
keyword == null or "".equals(keyword) 를 대체할 수 있다
<!-- 행을 만들고 -->
<div class="row my-3">
<!-- 4/12 인 칼럼을 만들고 margin-start:auto 를 부여해서 왼쪽 마진을 자동 부여한다 -->
<div class="col-lg-4 col-md-6 ms-auto">
<form action="list.jsp" method="get">
<div class="input-group">
<input value="<%=StringUtils.isEmpty(keyword) ? "":keyword%>" type="text" name="keyword" class="form-control" placeholder="검색어 입력"/>
<button type="submit" class="btn btn-outline-secondary bg-primary-subtle btn-sm"><i class="bi bi-search"></i></button>
</div>
</form>
</div>
</div>
<ul class="pagination">
<%-- startPageNum 이 1이 아닐때 이전 page 가 존재하기 때문에... --%>
<%if(startPageNum != 1){ %>
<li class="page-item">
<a class="page-link" href="list.jsp?pageNum=<%=startPageNum-1 %>&keyword=<%=keyword %>">‹</a>
</li>
<%} %>
<%for(int i=startPageNum; i<=endPageNum ; i++){ %>
<li class="page-item">
<a class="page-link <%= i==pageNum ? "active":"" %>" href="list.jsp?pageNum=<%=i %>&keyword=<%=keyword %>"><%=i %></a>
</li>
<%} %>
<%-- endPageNum 이 totalPageCount 보다 작을때 다음 page 가 있다 --%>
<%if(endPageNum < totalPageCount){ %>
<li class="page-item">
<a class="page-link" href="list.jsp?pageNum=<%=endPageNum+1 %>&keyword=<%=keyword %>">›</a>
</li>
<%} %>
</ul>
⚠️ html 속성의 구조와 삼항 연산자 , <%=%> 잘 알아두기
CREATE TABLE comments(
num NUMBER PRIMARY KEY, -- 댓글의 글번호
writer VARCHAR2(20) NOT NULL, -- 작성자
content VARCHAR2(100) NOT NULL, -- 내용
targetWriter VARCHAR2(20) NOT NULL, -- 누구에게 작성한 댓글인지
groupNum NUMBER NOT NULL, -- 댓글의 그룹번호
parentNum NUMBER NOT NULL, -- 부모가 되는 원글의 글번호
deleted CHAR(3) DEFAULT 'no', -- 댓글을 삭제했는지 여부
createdAt DATE DEFAULT SYSDATE -- 댓글 작성일
);
CREATE SEQUENCE comments_seq;
public class CommentDto {
private int num;
private String writer;
private String cotent;
private String targetWriter;
private int groupNum;
private int parentNum;
private String deleted;
private String createdAt;
// setter, getter
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getWriter() {
return writer;
}
public void setWriter(String writer) {
this.writer = writer;
}
public String getCotent() {
return cotent;
}
public void setCotent(String cotent) {
this.cotent = cotent;
}
public String getTargetWriter() {
return targetWriter;
}
public void setTargetWriter(String targetWriter) {
this.targetWriter = targetWriter;
}
public int getGroupNum() {
return groupNum;
}
public void setGroupNum(int groupNum) {
this.groupNum = groupNum;
}
public int getParentNum() {
return parentNum;
}
public void setParentNum(int parentNum) {
this.parentNum = parentNum;
}
public String getDeleted() {
return deleted;
}
public void setDeleted(String deleted) {
this.deleted = deleted;
}
public String getCreatedAt() {
return createdAt;
}
public void setCreatedAt(String createdAt) {
this.createdAt = createdAt;
}
}
<h4>댓글을 입력해 주세요</h4>
<!-- 원글의 댓글을 작성할 폼 -->
<form action="save-comment.jsp" method="post">
<input type="hidden" name="parentNum" value="<%=dto.getNum()%>"/>
<input type="hidden" name="targetWriter" value="<%=dto.getWriter()%>"/>
<textarea name="content" rows="10"></textarea>
<button type="submit">등록</button>
</form>