# 환경구성
1. 워크스페이스 만들기
c드라이브에
2. DB 설정
- 관리자 계정에서 계정 만들기
create user mybatis identified by mybatis;
grant resource, connect to mybatis;
- 계정에 접속해 테이블생성하기
슬랙-공지-Table Scripts.sql
3. mybatis.jar파일 다운로드
=> lib폴더에 넣어주기
# 회원가입
<index.jsp>
* 프레임워크
- 개발자가 보다 편리한 환경에서 개발할 수 있도록 제공하는 뼈대, 틀이라고 생각
- 소프트웨어 개발의 입장에서는 공통으로 사용하는 라이브러리/개발도구/인터페이스 등등
* 프레임워크의 필요성
- 웹 프로그램의 규모가 커지고 있음
=> 거대하고 복잡도가 높은 프로젝트를 완성시키기 위해 많은 사람들이 필요함
=> 개발자들이 "통일성"있게 "빠르고", "안정적"으로 개발하기 위한 한 가지 방법으로 프레임워크가 좋은 성과를 내고 있음
=> 생산성 향상에 큰 도움이 된다.
* 프레임워크의 특징
- 자유롭게 설계하고 코드를 짜는 것이 아니라 프레임워크가 제공하는 가이드대로 설계하고 코드를 짜야함(셋팅도)
- 개발할 수 있는 범위가 정해져있음
- 개발자를 위한 다양한 도구 / 플러그인들이 지원됨
* 프레임 워크의 장단점
> 장점 : 개발시간을 줄일 수 있음
오류로부터 자유로워질 수 있음
> 단점 : 너무 의존하다보면 개발능력이 떨어져서 프레임워크 없이 개발하는 것이 어려워짐
습득하는데까지 시간이 오래걸릴 수 있음
* 프레임워크의 종류
- 영속성 : 데이터관련한(CRUD)기능들을 편리하게 작업할 수 있도록 하는 프레임워크
ex) MyBatis, Hibernate..
- 자바 : 웹 어플리케이션에 초점에 맞춰 필요한 요소들을 모듈화해서 제공하는 프레임워크
ex) Spring, Struts
- 화면 구현 : Front-end를 보다 쉽게 구현할 수 있게 틀을 제공해주는 프레임워크
ex) Bootstrap..
- 기능 및 지원 : 특정 기능이나 업무수행에 도움을 주는 기능을 제공해주는 프레임워크
ex) Log4j, JUnit...
<index.jsp>
WEB-INF 파일 밑에 있는 구성들은 직접접근이 불가능 함
예 http://localhost:8004/mybatis/WEB-INF/views/main.jsp
와 같은 경로로 접속할 수 없음
그럼 어떻게 접근해야할까?
=> index.jsp에 main페이지를 포워딩 해주기
<jsp:forward page="WEB-INF/views/main.jsp"/>
url은 그대로지면 실제 화면은 내가 포워딩한 페이지로 나옴
** 이전시간에 배웠던 포워딩 활용방법
<main.jsp>
<jsp:include page="common/menubar.jsp"/>
- menubar include해주기
** 절대경로/상대경로 다시 공부하기
<menubar.jsp>
<c:choose>
<c:when test="${empty loginUser}">
<!-- case1. 로그인 전 -->
<form action="" method="post">
<table>
<tr>
<td>아이디</td>
<td><input type="text" name="userId" required/></td>
<td rowspan="2"> <button type="submit" style="height: 60px;">로그인</button></td>
</tr>
<tr>
<td>비밀번호</td>
<td><input type="password" name="userPwd" required></td>
</tr>
<tr>
<td colspan="3" align="center">
<a href="enrollForm.me">회원가입</a>
</td>
</tr>
</table>
</form>
</c:when>
<c:otherwise>
<!-- case2. 로그인 후 -->
<table>
<tr>
<td colspan="2">
<h3>~님 환영합니다.</h3>
</td>
</tr>
<tr>
<td><a href="">마이페이지</a> </td>
</tr>
</table>
</c:otherwise>
</c:choose>
- 조건문을 사용해서 비회원/ 회원 상태에 따라 화면 다르게 지정
** 주의 choose와 주석 함께 쓰지 않기
"회원가입"버튼 클릭 시 enrollForm.me매핑값으로 이동
request.getRequestDispatcher("WEB-INF/views/member/memberEnrollForm.jsp").forward(request, response);
<WEB-INF/views/member/memberEnrollForm.jsp>
<form action="insert.me" method="post">
<table align="center">
<tr>
<td>* ID</td>
<td><input type="text" name="userId" required></td>
</tr>
<tr>
<td>* PWD</td>
<td><input type="password" name="userPwd" required></td>
</tr>
<tr>
<td>* NAME</td>
<td><input type="text" name="userName" required></td>
</tr>
<tr>
<td> EMAIL</td>
<td><input type="email" name="email"></td>
</tr>
<tr>
<td> BIRTHDAY</td>
<td><input type="text" name="birthday" placeholder="생년월일(6자리)"></td>
</tr>
<tr>
<td> GENDER</td>
<td align="center">
<input type="radio" name="gender" value="M" checked> 남
<input type="radio" name="gender" value="F"> 여
</td>
</tr>
<tr>
<td> PHONE</td>
<td><input type="text" name="phone" placeholder="-포함"></td>
</tr>
<tr>
<td> ADDRESS</td>
<td><input type="text" name="address"></td>
</tr>
</table>
<br>
<div align="center">
<button type="reset">초기화</button>
<button type="submit">회원가입</button>
</div>
</form>
submit버튼을 누르면 input태그에 담긴 value값과 함께 form태그의 action속성에 쓰인 매핑값으로 이동
<MemberInsertController> : /insert.me
request.setCharacterEncoding("UTF-8");
Member m = new Member();
m.setUserId(request.getParameter("userId"));
m.setUserPwd(request.getParameter("userPwd"));
m.setUserName( request.getParameter("userName"));
m.setEmail(request.getParameter("email"));
m.setBirthDay(request.getParameter("birthDay"));
m.setGender(request.getParameter("gender"));
m.setPhone(request.getParameter("phone"));
m.setAddress(request.getParameter("address"));
if(new MemberServiceImpl().insertMember(m)>0) {
response.sendRedirect(request.getContextPath());
}else { //실패했을 경우 에러페이지(에러문구 담아서)
request.setAttribute("errorMsg", "회원가입실패");
request.getRequestDispatcher("WEB-INF/views/common/errorPage.jsp");
}
<MemberService>
앞으로 Service는 인터페이스와 인터페이스 구현 클래스를 만들 것.
이유는 ?
=> 유지보수를 위해 분리하기 ! 메소드들의 틀을 미리 만들어 개발자 간의 의사소통 혼선을 줄여주고 다형성 개발의 유리함을 가져올 수 있음 !
* 인터페이스 : 상수필드(public static final) + 추상메소드(public abstract)
public interface MemberService {
//회원가입용 메소드
int insertMember(Member m);
//로그인용 메소드
Member loginMember(Member m);
//회원정보수정용 메소드
int updateMember(Member m);
//회원탈퇴용 메소드
int deleteMember(Member m);
}
<MemberServiceImple>
인터페이스 구현 클래스
항상 매개변수는 한 개 이상 받지 않는다 ** 만약 여러개면 어디에 담아서 하나로 보내야함
왜???? => 오버라이딩때문에?..
private MemberDao memberDao = new MemberDao();
@Override
public int insertMember(Member m) {
SqlSession sqlSession = Template.getSqlSession();
int result = memberDao.insertMember(sqlSession, m);
if(result>0) sqlSession.commit();
// 트랜잭션이 애초에 생기지 않기 떄문에 할 필요 없음
sqlSession.close();
return result;
}
앞으로 모든 mybatis관련 파일들은 소스파일폴더인
이곳에 넣을 것!!
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
이 문서의 형식이 contiguration(=환경설정)임을 알려줌
=> configuration 태그가 전체를 감싸고 있음
DTD : 유효성을 체크해줌 (내부 태그들이 configuration태그 안에 존재할 수 있는지 체크)
- < contiguration> 태그로 감싸져있음,
- setting : MyBatis를 구동 시 설정들을 작성하는 영역
<configuration>
<settings>
<!-- 만약 null로 데이터가 전달이 되었다면 빈칸이 아닌 NULL로 인식하겠다.(무조건 대문자 NULL로 작성해야함) -->
<setting name="jdbcTypeForNull" value="NULL" />
</settings>
- typeAlias : VO/DTO 클래스들의 풀클래스명을 단순한 클래스명으로 사용하기위해서 별칭을 등록할 수 있는 영역
<typeAliases>
<typeAlias type="com.kh.mybatis.member.model.vo.Member" alias="member"/>
<typeAlias type="com.kh.mybatis.board.model.vo.Board" alias="board"/>
<typeAlias type="com.kh.mybatis.board.model.vo.Reply" alias="Reply"/>
</typeAliases>
- environment : MyBatis에서 연동할 DB정보들을 등록하는 영역 (여러개의 DB정보를 등록 가능)
=> default속성으로 여러개의 id중 어떤 DB를 기본 DB로 사용할 건지 꼭 지정을 해줘야한다.
- transactionManeger는 JDBC와 MANAGED 둘 중 하나를 선택할 수 있음
JDBC : 트랜잭션을 내가 직접 관리하겠다 (수동 commit)
MANAGED : 개발자가 트랜잭션에 대한 어떤 양행도 행사하지 않겠다 (자동 commit)
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
- dataSource로는 POOLED와 UPPOOLED 둘 중 하나를 선택할 수 있음(ConnectionPool 사용여부)
> ConnectionPool : Connection 객체를 담아둘 수 있는 영역
한 번 생성된 Connection객체를 담아두면 재사용해서 쓸 수 있음
=> POOLED : ConnectionPool 사용
=> UNPOOLED : ConnectionPool 사용X
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
<property name="username" value="mybatis"/>
<property name="password" value="mybatis"/>
</dataSource>
</environment>
</environments>
- mapper:실행할 sql문들을 기록해둔 mapper파일 등록하는 영역
<mappers>
<mapper resource = "/mappers/member-mapper.xml"/>
<mapper resource = "/mappers/board-mapper.xml"/>
</mappers>
주의** 꼭 만들고 나서!!!! 등록하기 (위에 VO도 마찬가지)
<com.kh.mybatis.member.model.dao>
sqlSession에서 제공하는 메소드를 통해 sql문을 찾아서 실행하고 결과를 바로 받아볼 수 있다.
sqlSession.sql문 종류에 맞는 메소드("mapper파일의 namespace.해당sql문의 고유한 id");
public int insertMember(SqlSession sqlSession, Member m) {
return sqlSession.insert("memberMapper.insertMember", m);
}
<memberMapper>
* DML문일 경우
<insert id="각 sql문의 식별자" parameterType="전달받을자바타입(풀클래스명) 혹은 별칭">
쿼리문 작성
</insert>
=> parameterType속성은 전달받을 값이 없다면 생략 가능하다
<update></update>
<delete></delete>
모두 int로 돌아오기 때문에 따로 작성할 필요없음
* SELECT문일 경우
<select id="각 sql문의 식별자" parameterType="전달받은 자바타입(풀클래스명) 혹은 별칭"
resultType="조회결과를 반환하고자 하는 자바 타입" 또는 resultMap="조회결과를 뽑아서 매핑할 resultMap의 id">
쿼리문 작성
</select>
=> parameterType속성은 전달받을 값이 없다면 생략이 가능하다.
=> 반드시 resultType(자바에서 제공하는 자료형) 또는 resultMap(내가 만든 VO클래스 타입)으로 결과에 대한 타입을 지정해야 함
=> 왜? SELECT문의 결과는 항상 어떤 SELECT문이냐에 따라서 다를 수 있기 때문에 (COUNT()를 쓰면 정수/name만 조회하면 문자열)
그동안은 pstmt객체를 이용해서 ?(위치홀더)를 사용했지만,
앞으로는 위치홀더 대신 해당 SQL문에 전달된 객체로부터 값을 꺼내서 사용
꺼내는 방법 #{필드명 또는 변수명 또는 map의 키값)을 이용
- namespace : 해당 mapper의 고유한 별칭 전체가 mapper태그로 감싸져 있어야 한다.
<mapper namespace="memberMapper">
<insert id="insertMember" parameterType="member">
INSERT
INTO
MEMBER
(
USER_NO,
USER_ID,
USER_PWD,
USER_NAME,
EMAIL,
BIRTHDAY,
GENDER,
PHONE,
ADDRESS
)
VALUES
(
SEQ_UNO.NEXTVAL,
#{userId},
#{userPwd},
#{userName},
#{email},
#{birthDay},
#{gender},
#{phone},
#{address}
)
<!-- 내부적으로 getter 메소드를 불러옴 -->
</insert>
# 로그인
<form action="login.me" method="post">
<table>
<tr>
<td>아이디</td>
<td><input type="text" name="userId" required/></td>
<td rowspan="2"> <button type="submit" style="height: 60px;">로그인</button></td>
</tr>
<tr>
<td>비밀번호</td>
<td><input type="password" name="userPwd" required></td>
</tr>
<tr>
<td colspan="3" align="center">
<a href="enrollForm.me">회원가입</a>
</td>
</tr>
</table>
</form>
아이디와 비밀번호를 입력 후 submit버튼 클릭 시 login.me로 요청
<LoginController> /login.me
Member m = new Member();
m.setUserId(request.getParameter("userId"));
m.setUserPwd(request.getParameter("userPwd"));
Member loginUser = new MemberServiceImpl().loginMember(m);
//unique제약조건이 걸려있기때문에 member로 돌려줄 수 밖에 없음
if(loginUser == null) {
request.setAttribute("errorMsg", "로그인실패");
request.getRequestDispatcher("WEB-INF/views/common/errorPage.jsp").forward(request, response);
}else {
request.getSession().setAttribute("loginUser", loginUser);
response.sendRedirect(request.getContextPath());
}
<MemberServiceImpl>
@Override
public Member loginMember(Member m) {
SqlSession sqlSession = Template.getSqlSession();
Member loginUser = memberDao.loginUser(sqlSession, m);
sqlSession.close();
return loginUser;
}
<MemberDao>
- selectOne() : 조회결과가 없다면 null반환 ***=> 초기화 안해도된
- selectOne이나 selectList 딱 두가지 기억하기 !!
조회결과가 하나 돌아온다면 selectOne, 두개 이상이면 selectList
public Member loginUser(SqlSession sqlSession, Member m) {
return sqlSession.selectOne("memberMapper.loginUser", m);
}
<member-Mapper>
* resultMap : Mybatis의 핵심 기능 중 하나
ResultSet으로부터 조회된 컬럼값을 하나씩 뽑아서
내가 지정한 VO객체에 각 필드에 담는 JDBC코드를 줄여주는 역할 수행
<resultMap id="식별자" type="조회된 결과를 담아서 반환하고자하는 VO객체의 타입(풀클래스명) 또는 별칭">
<result column="조회결과를 뽑고자하는 DB컬럼명" property="해당 결과를 담고자 하는 필드명" />
<result column="조회결과를 뽑고자하는 DB컬럼명" property="해당 결과를 담고자 하는 필드명" />
...
</resultMap>
<resultMap id="MemberResultSet" type="member">
<result column="USER_NO" property="userNo"/>
<result column="USER_ID" property="userId"/>
<result column="USER_PWD" property="userPwd"/>
<result column="USER_NAME" property="userName"/>
<result column="EMAIL" property="email"/>
<result column="BIRTHDAY" property="birtyDay"/>
<result column="GENDER" property="gender"/>
<result column="PHONE" property="phone"/>
<result column="ADDRESS" property="address"/>
<result column="ENROLL_DATE" property="enrollDate"/>
<result column="MODIFY_DATE" property="modifyDate"/>
<result column="STATUS" property="status"/>
</resultMap>
=> 내부적으로 필드에 대한 setter메소드를 호출
<select id="loginUser" parameterType="member" resultMap="MemberResultSet">
만약, resultType을 사용하면?
<select id="loginUser" parameterType="member" resultType="member">
SELECT
USER_NO userNo,
USER_ID userId,
USER_PWD userPwd,
USER_NAME userName,
EMAIL email,
BIRTHDAY birthDay,
GENDER gender,
PHONE phone,
ADDRESS address,
ENROLL_DATE enrollDate,
MODIFY_DATE modifyDate,
STATUS status
FROM
MEMBER
WHERE
USER_ID = #{userId}
AND
USER_PWD = #{userPwd}
AND
STATUS = 'Y'
</select>
# 일반게시글 리스트 조회
<menubar.jsp>
<div class="menu" onclick="location.href='list.bo?currentPage=1'">게시판</div>
onclick속성을 줘서 요청 보내기 (페이징바 처리를 위해서 currentPage도 쿼리스트링으로 함께 보내기)
<BoardListController> : /list.bo
--------------------페이징 처리-----------------------
int listCount = new BoardServiceImpl().selectListCount();
int currentPage = Integer.parseInt(request.getParameter("currentPage"));
int pageLimit = 10;
int boardLimit = 5;
PageInfo pi = Pagination.getPageInfo(listCount, currentPage, pageLimit, boardLimit);
maxPage, startPage, endPage는 위의 변수들로 구하는 것.
공식은 같기에 협업할 때 템플릿을 만들어놓고 함께 사용하기 (**파이널 때 참고)
<Pageination>
public static PageInfo getPageInfo(int listCount, int currentPage, int pageLimit, int boardLimit) {
int maxPage = (int)Math.ceil(((double)listCount/boardLimit));
int startPage = (currentPage-1)/pageLimit * pageLimit + 1;
int endPage = startPage + pageLimit - 1;
if(endPage > maxPage) {
endPage = maxPage;
}
PageInfo pi = new PageInfo(listCount, currentPage, pageLimit, boardLimit,
maxPage, startPage, endPage);
return pi;
}
구한 페이징바 정보를 가지고 BoardList조회하러 가기
ArrayList<Board> list = new BoardServiceImpl().selectList(pi);
request.setAttribute("list", list);
request.setAttribute("pi", pi);
request.getRequestDispatcher("WEB-INF/views/board/boardListView.jsp").forward(request, response);
왜 어떤건 if(list == null) 처리해주고 안해주지?
<BoardService> : 인터페이스
public interface BoardService {
//게시글 관련 서비스
int selectListCount();
ArrayList<Board> selectList(PageInfo pi);
int increaseCount(int BoardNo);
Board selectBoard(int BoardNo);
ArrayList<Reply> selectReplyList(int boardNo);
}
<BoardServiceImpl> : 인터페이스 구현
public class BoardServiceImpl implements BoardService{
private BoardDao boardDao = new BoardDao();
@Override
public int selectListCount() {
SqlSession sqlSession = getSqlSession();
int listCount = boardDao.selectListCount(sqlSession);
sqlSession.close();
return listCount;
}
@Override
public ArrayList<Board> selectList(PageInfo pi) {
SqlSession sqlSession = getSqlSession();
ArrayList<Board> list = boardDao.selectList(sqlSession, pi);
sqlSession.close();
return list;
}
<BoardDao>
myBatis에서 페이징 처리를 위해서 RowBounds라는 클래스를 제공
* offset : 몇 개의 게시글을 건너뛰고 조회할건지 대한 값
ex) boardLimit이 5일 경우
offset(건너뛸 숫자) boardLimit(조회할 숫자)
currentPage : 1 => 1~5 0 5
currentPage : 2 => 6~10 5 5
currentPage : 3 => 11~14 10 5
currentPage-1*boardLimit = offset
public int selectListCount(SqlSession sqlSession) {
return sqlSession.selectOne("boardMapper.selectListCount");
}
public ArrayList<Board> selectList(SqlSession sqlSession, PageInfo pi) {
int offset = (pi.getCurrentPage()-1)*pi.getBoardLimit();
RowBounds rowBounds = new RowBounds(offset, pi.getBoardLimit());
return (ArrayList)sqlSession.selectList("boardMapper.selectList",null, rowBounds);
}
RowBounds객체를 넘겨야 할 경우
selectList메소드의 오버로딩된 형태 중 매개변수가 3개인 메소드를 반드시 사용해야 함
딱히 두 번쨰 매개변수 자리에 넘길 값이 없다면 null을 넘겨줌 / null"값"
<mapper namespace="boardMapper">
<resultMap id="boardResultSet" type="board">
<result column="BOARD_NO" property="boardNo"/>
<result column="BOARD_TITLE" property="boardTitle"/>
<result column="USER_ID" property="boardWriter"/>
<result column="COUNT" property="count"/>
<result column="CREATE_DATE" property="createDate"/>
<result column="BOARD_CONTENT" property="boardContent"/>
</resultMap>
<!-- 컬럼에 있어야 찾아가기 때문에 내가 조회한 값이 없어도 쓸 수 있음 -->
<select id="selectListCount" resultType="_int">
SELECT
COUNT(*)
FROM
BOARD
WHERE
STATUS = 'Y'
</select>
<select id="selectList" resultMap="boardResultSet">
SELECT
BOARD_NO,
BOARD_TITLE,
USER_ID,
COUNT,
CREATE_DATE
FROM
BOARD B
JOIN
MEMBER ON(BOARD_WRITER = USER_NO)
WHERE B.STATUS = 'Y'
ORDER
BY
BOARD_NO DESC
</select>
이전 방법과 차이점 : 모두 다 조회해와서 이곳에서 잘라서 넘겨줌(DB가 아니라) but,데이터가 많으면 부하가 발생할 수 있음
return (ArrayList)sqlSession.selectList("boardMapper.selectList",null, rowBounds);
# 게시글 상세 조회
<td><a href="detail.bo?bno=${b.boardNo}">${b.boardTitle }</a></td>
=> 글 제목을 클릭 시 detail.bo로 이동하도록 a태그로 지정
<BoardDetailController> : / detail.bo
int boardNo = Integer.parseInt(request.getParameter("bno"));
BoardService boardService = new BoardServiceImpl();
다형성 (부모-자식) boardService는 추상메소드만 가지고 있음 유지보수를 줄일 수 있음 (어차피 모든 메소드를 오버라이딩 해야하기 떄문에 기능은 그대로 있고 수정한 부분만 반영됨.)
1. 조회수를 증가시키는 서비스
2. 해당 게시글을 상세조회하는 서비스
if(boardService.increaseCount(boardNo)>0) {
request.setAttribute("count", boardService.increaseCount(boardNo));
request.setAttribute("b",boardService.selectBoard(boardNo) );
- 조회수 증가와 게시글 조회
3. 해당 게시글에 딸린 댓글들을 조회하는 서비스
request.setAttribute("list",boardService.selectReplyList(boardNo) );
request.getRequestDispatcher("WEB-INF/views/board/boardDetailView.jsp").forward(request, response);
4. 조회실패 시
}else {
request.setAttribute("errorMsg", "게시글 상세조회 실패");
request.getRequestDispatcher("WEB-INF/views/common/errorPage.jsp").forward(request, response);
}
<BoardServiceImpl>
@Override
public int increaseCount(int boardNo) {
SqlSession sqlSession = getSqlSession();
int result = boardDao.increaseCount(sqlSession, boardNo);
if(result>0) sqlSession.commit();
sqlSession.close();
return result;
}
@Override
public Board selectBoard(int boardNo) {
SqlSession sqlSession = getSqlSession();
Board b = boardDao.selectBoard(boardNo, sqlSession);
sqlSession.close();
return b;
}
@Override
public ArrayList<Reply> selectReplyList(int boardNo) {
SqlSession sqlSession = getSqlSession();
ArrayList<Reply> Rlist = boardDao.selectReplyList(sqlSession, boardNo);
sqlSession.close();
return Rlist;
}
<BoardDao>
public int increaseCount(SqlSession sqlSession, int boardNo) {
return sqlSession.update("boardMapper.increaseCount", boardNo);
}
public Board selectBoard(int boardNo, SqlSession sqlSession) {
return sqlSession.selectOne("boardMapper.selectBoard", boardNo);
}
public ArrayList<Reply> selectReplyList(SqlSession sqlSession, int boardNo) {
return (ArrayList)sqlSession.selectList("boardMapper.selectReplyList", boardNo);
}
<board-mapper.xml>
<resultMap id="replyResultSet" type="reply">
<result column="REPLY_NO" property="replyNo"/>
<result column="REPLY_CONTENT" property="replyContent"/>
<result column="REF_BNO" property="refBno"/>
<result column="USER_ID" property="replyWriter"/>
<result column="CREATE_DATE" property="createDate"/>
</resultMap>
<update id="increaseCount" parameterType="_int">
UPDATE
BOARD
SET
COUNT = COUNT + 1
WHERE
BOARD_NO = #{boardNo}
AND
STATUS = 'Y'
</update>
<select id="selectBoard" parameterType="_int" resultMap="boardResultSet">
SELECT
BOARD_NO,
BOARD_TITLE,
USER_ID,
COUNT,
CREATE_DATE,
BOARD_CONTENT
FROM
BOARD B
JOIN
MEMBER ON(BOARD_WRITER = USER_NO)
WHERE
BOARD_NO = #{boardNo}
AND
B.STATUS = 'Y'
</select>
<select id="selectReplyList" parameterType="_int" resultMap="replyResultSet">
SELECT
REPLY_NO,
REPLY_CONTENT,
REF_BNO,
USER_ID,
CREATE_DATE
FROM
REPLY R
JOIN
MEMBER ON(USER_NO = REPLY_WRITER)
WHERE
REF_BNO = #{boardNo}
AND
R.STATUS = 'Y'
</select>
'클라우드 융합 Full-stack 웹 개발자 양성과정 > Spring' 카테고리의 다른 글
Spring - 마이페이지(수정), 회원탈퇴, 게시글리스트조회 (0) | 2022.12.23 |
---|---|
Spring - 로그인, 로그아웃, 회원가입 (0) | 2022.12.20 |
Spring - 개발환경구성 (0) | 2022.12.20 |
MyBatis - 검색, filter기능 (0) | 2022.12.19 |
EL표현언어, JSTL (9) | 2022.12.13 |