JSON 형식으로 값 반환
presentation-layer.xml
<!-- HttpMessageConverter를 구현한 모든 변환기가 생성된다 -->
<!-- 자바객체를 JSON응답 보디로 변환할 때는 MappingJackson2HttpMessageConverter를 사용한다 -->
<!-- 스프링 컨테이너가 어노테이션 처리를 해준다, 우리가 직접 MappingJackson2HttpMessageConverter을 사용하는 것이 아님.-->
<mvc:annotation-driven></mvc:annotation-driven>
Boardcontroller.java
// 글 목록 JSON으로 변환
@RequestMapping(value = "/dataTransform.do")
// @ResponseBody 어노테이션을 사용하여 자바 객체를 HTTP 응답 본문의 객체로 변환하며 클라이언트로 전송한다
@ResponseBody // 자바형식을 제이슨형식으로 바꿔달라고 요청
public List<BoardVO> dataTransform(BoardVO vo){
vo.setSearchCondition("TITLE");
vo.setSearchKeyword("");
List<BoardVO> boardList = boardService.getBoardList(vo);
return boardList;
}
JSON 형식으로 값을 받아오는 화면
getBoardListJson.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<style>
table {
width: 100%;
border-collapse: collapse;
}
th, td {
border: 1px solid #dddddd;
text-align: left;
padding: 8px;
}
th {
background-color: #f2f2f2;
}
</style>
<script>
$(document).ready(function() {
$.ajax({
url : 'dataTransform.do',
method : 'GET',
dataType : 'json',
success : function(data) {
var tableBody = $('#boardTable tbody');
data.forEach(function(item) {
var row = $('<tr></tr>');
row.append('<td>' + item.seq + '</td>');
row.append('<td>' + item.title + '</td>');
row.append('<td>' + item.writer + '</td>');
row.append('<td>' + item.content + '</td>');
row.append('<td>' + item.cnt + '</td>');
tableBody.append(row);
});
},
error : function(xhr, status, error) {
console.error('Error fetching data:', error);
}
});
});
</script>
</head>
<body>
<table id="boardTable">
<thead>
<tr>
<td>번호</td>
<td>제목</td>
<td>작성자</td>
<td>내용</td>
<td>조회수</td>
</tr>
</thead>
<tbody>
<!-- 값을 받아오는 곳 -->
</tbody>
</table>
</body>
</html>
페이징 기능 추가
페이징 기능 추가를 과제로 해봤는데 너무 어려웠다ㅠ 잘 동작하지 않았고 챗 GPT한테 물어보며 코드를 수정하는 바람에 더 복잡해졌다.
하다 너무 어려우면 했던 걸 다시 복습하는 게 나을 것 같다.
이걸 잘 못한 이유도 결국 전에 코드를 내가 다 짠 게 아니라 강사님 코드를 따라 치고 내 것으로 못 만들어서 그런거니..
각설하고 일단 잘못된 코드라도 기록해 놓는다. 또 수정하다 보면 어디서 뭐가 잘못됐는지 잊혀지니 여기에 써 놓기로.
∨ 페이징 기능 추가 전 BoardDAOSpring.java 코드
package com.springbook.biz.board.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import com.springbook.biz.board.BoardVO;
// 비즈니스 계층에서 사용할 수 있도록 빈에 등록
@Repository
public class BoardDAOSpring {
@Autowired
private JdbcTemplate jdbcTemplate;
// 상수형태로 만들어 두었다.
private final String BOARD_INSERT = " insert into board(seq, title, writer, content) values "
+ " ((select nvl(max(seq),0) + 1 from board), ?, ?, ?)";
private final String BOARD_UPDATE = "update board set title=?, content=? where seq=?";
private final String BOARD_DELETE = "delete board where seq=?";
private final String BOARD_GET = "select * from board where seq=?";
private final String BOARD_LIST = "select * from board order by seq desc";
// 검색기능
private final String BOARD_LIST_T = "select * from board where title like '%'||?||'%' order by seq desc";
private final String BOARD_LIST_C = "select * from board where content like '%'||?||'%' order by seq desc";
// ---------- update() 구문 사용 ----------
// 글 등록
public void insertBoard(BoardVO vo) {
System.out.println("===> springJDBC로 insertBoard() 기능 처리");
// insert를 springJDBC에서는 update가 처리, try catch문 사용 안해도 됨.
// 기존 jdbc 에서 사용한 '?' 대신 순서대로 객체를 가지고 와 적어준다.
// jdbcTemplate.update(BOARD_INSERT, vo.getTitle(), vo.getWriter(), vo.getContent());
jdbcTemplate.update(BOARD_INSERT, vo.getTitle(), vo.getWriter(), vo.getContent());
}
// 글 수정
public void updateBoard(BoardVO vo) {
System.out.println("===> springJDBC로 updateBoard() 기능 처리");
jdbcTemplate.update(BOARD_UPDATE, vo.getTitle(), vo.getContent(), vo.getSeq());
}
// 글 삭제
public void deleteBoard(BoardVO vo) {
System.out.println("===> springJDBC로 deleteBoard() 기능 처리");
jdbcTemplate.update(BOARD_DELETE, vo.getSeq());
}
// ---------- queryForObject(), query() 구문 사용 ----------
// 글 상세 조회
public BoardVO getBoard(BoardVO vo) {
System.out.println("===> springJDBC로 getBoard() 상세 보기 처리");
// 배열로 값을 받기 때문에 배열에 넣어준다
Object[] args= {vo.getSeq()};
// return jdbcTemplate.queryForObject(sql, args, rowMapper);
return jdbcTemplate.queryForObject(BOARD_GET, args, new BoardRowMapper());
}
// 글 목록 조회
public List<BoardVO> getBoardList(BoardVO vo) {
System.out.println("==> springJDBC로 getBoardList() 기능 처리");
Object[] args = {vo.getSearchKeyword()};
if (vo.getSearchCondition().equals("TITLE")) {
return jdbcTemplate.query(BOARD_LIST_T, args, new BoardRowMapper());
} else if (vo.getSearchCondition().equals("CONTENT")) {
return jdbcTemplate.query(BOARD_LIST_C, args, new BoardRowMapper());
}
return null;
}
}
동작 되지 않는 코드
∨ BoardController.java
package com.springbook.view.board;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
//import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.multipart.MultipartFile;
import com.springbook.biz.board.BoardService;
import com.springbook.biz.board.BoardVO;
//import com.springbook.biz.board.impl.BoardDAO;
import com.springbook.biz.board.PageDTO;
//import oracle.net.aso.l;
@Controller // web.xml에 있는 프론트컨트롤러를 읽어준다
@SessionAttributes("board") // 저장할 때 "board"라는 이름의 객체가 있으면 session 영역에 저장
public class BoardController {
// 통합 컨트롤러
// 변수 선언 - 변수만 선언해서는 아무 정보도 가지고 올 수 없음
// 자동의존주입 방식으로 정보 주입
@Autowired
// private BoardDAO boardDAO;
private BoardService boardService;
// 글 목록 JSON으로 변환
@RequestMapping(value = "/dataTransform.do")
// @ResponseBody 어노테이션을 사용하여 자바 객체를 HTTP 응답 본문의 객체로 변환하며 클라이언트로 전송한다
@ResponseBody // 자바형식을 제이슨형식으로 바꿔달라고 요청
public List<BoardVO> dataTransform(BoardVO vo){
vo.setSearchCondition("TITLE");
vo.setSearchKeyword("");
List<BoardVO> boardList = boardService.getBoardList(vo);
return boardList;
}
// @ModelAttribute 의 특징
// @RequestMapping 메소드가 실행 되기 전에 실행된다.
// @ModelAttribute 메소드의 실행 결과로 리턴되어지는 객체는 자동으로 Model에 저장된다.
// @ModelAttribute 메소드의 실행을 View페이지에서 사용할 수 있다.
@ModelAttribute("conditionMap") // ("") <- View 페이지에서 사용할 이름
public Map<String, String> searchConditionMap() {
Map<String, String> conditionMap = new HashMap<>();
conditionMap.put("제목", "TITLE");
conditionMap.put("내용", "CONTENT");
return conditionMap;
}
// 글 등록
@RequestMapping(value = "/insertBoard.do")
public String insertBoard(BoardVO vo) throws IllegalStateException, IOException { // BoardVO vo가 커멘드 객체
//boardDAO.insertBoard(vo);
// 파일 업로드
MultipartFile uploadFile = vo.getUploadFile();
if (!uploadFile.isEmpty()) {
String fileName = uploadFile.getOriginalFilename();
uploadFile.transferTo(new File("c://work//uploads//" + fileName)); // 파일 위치 경로
}
boardService.insertBoard(vo);
return "redirect:getBoardList.do";
}
// --------- 페이징 ---------
@GetMapping("/paging")
public String paging(Model model,
@RequestParam(value = "page" , required = false , defaultValue = "1") int page){
int pageSize = 5;
List<BoardVO> pagingList = boardService.pageList(page,pageSize);
PageDTO pageDTO = boardService.pagingParam(page, pageSize);
model.addAttribute("boardList", pagingList); // pagingList -> 한 페이지에 들어갈 게시글의 갯수를 지정
model.addAttribute("paging" , pageDTO); // 한 번에 몇 개의 페이지를 보이게 할 것인지에 대한 설명
return "paging";
}
// 글 수정
// @ModelAttribute("board")으로 정보를 가지고 온다
// @SessionAttributes("board")와 실제 같은 값
// 수정한 정보는 vo에 들어있다.
// 한번 들어온 객체들을 넣어두고
// 수정된 title, content는 나중에 처리
// 전체 데이터를 null 데이터 없이 넘겨 처리하기 위해선 이렇게 사용해야 한다.
@RequestMapping(value = "/updateBoard.do")
public String updateBoard(@ModelAttribute("board") BoardVO vo/* , BoardDAO boardDAO */) {
System.out.println(vo.getSeq());
System.out.println(vo.getTitle());
System.out.println(vo.getWriter());
System.out.println(vo.getContent());
System.out.println(vo.getRegDate());
System.out.println(vo.getCnt());
//boardDAO.updateBoard(vo);
boardService.updateBoard(vo);
return "redirect:getBoardList.do";
}
// 글 삭제
@RequestMapping(value = "/deleteBoard.do")
public String deleteBoard(BoardVO vo/* , BoardDAO boardDAO */) {
//boardDAO.deleteBoard(vo);
boardService.deleteBoard(vo);
return "redirect:getBoardList.do";
}
// 글 상세조회
@RequestMapping(value = "/getBoard.do")
public String getBoard(BoardVO vo/* , BoardDAO boardDAO */, Model model) {
model.addAttribute("board", boardService.getBoard(vo)); // model은 request 영역에 저장
return "getBoard.jsp";
}
// 글 목록 검색
// 커멘드 객체인 경우
@RequestMapping(value = "/getBoardList.do")
public String getBoardList(BoardVO vo/* , BoardDAO boardDAO */, Model model) {
if(vo.getSearchCondition() == null) {
vo.setSearchCondition("TITLE");
}
if(vo.getSearchKeyword() == null) {
vo.setSearchKeyword("");
}
model.addAttribute("boardList", boardService.getBoardList(vo));
return "getBoardList.jsp";
}
// 글 목록 검색
// 커멘드 객체가 아닌 경우
/*
* @RequestMapping(value = "/getBoardList.do") public String
* getBoardList(@RequestParam(value = "searchCondtion",defaultValue =
* "TITLE",required = false) String condition,
*
* @RequestParam(value = "searchKeyword",defaultValue = "CONTENT",required =
* false) String keyword, BoardVO vo, BoardDAO boardDAO, Model model) {
*
* System.out.println("검색 조건" + condition); System.out.println("검색 단어" +
* keyword);
*
* model.addAttribute("boardList", boardDAO.getBoardList(vo)); return
* "getBoardList.jsp"; }
*/
}
∨ BoardService
package com.springbook.biz.board;
import java.util.List;
public interface BoardService {
// crud
// 글 등록
void insertBoard(BoardVO vo);
// 글 수정
void updateBoard(BoardVO vo);
// 글 삭제
void deleteBoard(BoardVO vo);
// 글 상세조회
BoardVO getBoard(BoardVO vo);
// 글 목록 조회
List<BoardVO> getBoardList(BoardVO vo);
// 페이징 메소드
List<BoardVO> pageList(int page, int pageSize);
PageDTO pagingParam(int page, int pageSize);
}
∨ BoardServiceImpl
package com.springbook.biz.board.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.springbook.biz.board.BoardService;
import com.springbook.biz.board.BoardVO;
import com.springbook.biz.board.PageDTO;
import com.springbook.biz.board.boardRepository;
import jdk.nashorn.internal.ir.BlockLexicalContext;
@Service("boardService")
public class BoardServiceImpl implements BoardService {
// boardDAO를 의존 주입해야 한다.
@Autowired
private BoardDAOSpring boardDAO;
@Autowired
private BoardMapper boardMapper;
public BoardServiceImpl() {
}
@Override
public void insertBoard(BoardVO vo) {
boardDAO.insertBoard(vo);
}
@Override
public void updateBoard(BoardVO vo) {
boardDAO.updateBoard(vo);
}
@Override
public void deleteBoard(BoardVO vo) {
boardDAO.deleteBoard(vo);
}
@Override
public BoardVO getBoard(BoardVO vo) {
return boardDAO.getBoard(vo);
}
@Override
public List<BoardVO> getBoardList(BoardVO vo) {
return boardDAO.getBoardList(vo);
}
@Override
public List<BoardVO> pageList(int page, int pageSize) {
int pageStart = (page - 1) * pageSize;
return boardMapper.pageList(pageStart, pageSize);
}
@Override
public PageDTO pagingParam(int page, int pageSize) {
int boardCount = boardMapper.boardCount();
int maxPage = (int) Math.ceil((double) boardCount / pageSize);
int startPage = ((int) Math.ceil((double) page / blockLimit) - 1) * blockLimit + 1;
int endPage = startPage + blockLimit - 1;
if (endPage > maxPage) {
endPage = maxPage;
}
PageDTO pageDTO = new PageDTO();
pageDTO.setPage(page);
pageDTO.setStartPage(startPage);
pageDTO.setMaxPage(maxPage);
pageDTO.setEndPage(endPage);
return pageDTO;
}
}
∨ BoardMapper
package com.springbook.biz.board;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface BoardMapper {
@Select("SELECT * FROM board ORDER BY seq DESC LIMIT #{pageStart}, #{pageSize}")
List<BoardVO> pageList(@Param("pageStart") int pageStart, @Param("pageSize") int pageSize);
@Select("SELECT COUNT(*) FROM board")
int boardCount();
// 나머지 메서드들은 기존과 동일
}
정작 BoardDAOSpring은 수정하지 않았는데 접근 자체가 잘못된 것 같다.
다시 해보기 ㅠㅠ
MyBatis
- 쿼리문을 별도 관리, 분리한다
파일 만들기
여기서 next 를 누르고 조금 기다리면
이런 화면이 나온다
이 파란 부분 선택,
이렇게 설정해 파일을 만든다.
그 후 새로 만든 파일 new → 소스 폴더 누르고 stc/main/java 파일 만들기 → ojdbc6 (맥은 11) 연결하고 톰캣 서버 연결도 해주기.
maven 에서 mybatis, ibatis-core 라이브러리 두 개를 pom.xml에 추가한다.
MyBatis 에서는 BoardDAO에서 쓴 쿼리문을 그대로 사용,
기존 BoardDAO에서 ? 처리된 것을 기존에는 VO를 받아 처리했다면 여기서는 자동으로 VO를 받아와 #{}로 표기한다. 여기서는 VO.getTitle이런 식으로 쓰지 않음.
#{title} 이렇게 표기함으로서 의미를 함축
board-mapping.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="BoardDAO">
<!-- 글 등록 -->
<insert id="insertBoard">
insert into board (seq,title,writer,content)
values ((select nvl(max(seq),0) + 1 from board), #{title}, #{writer}, #{content})
</insert>
<!-- 글 수정 -->
<update id="updateBoard">
update board set title=#{title}, content=#{content}, where seq=#{seq}
</update>
<!-- 글 삭제 -->
<delete id="deleteBoard">
delete board where seq=#{seq}
</delete>
<!-- 글 상세 조회 -->
<select id="getBoard" resultType="board">
select * from board where seq=#{seq}
</select>
<!-- 글 목록 조회 -->
<select id="getBoardList" resultType="board">
select * from board where title like '%'||#{searchKeyword}||'%'
order by seq desc
</select>
</mapper>
태그 속성 자체에 기능의 이름이 붙으며 쿼리문 사용이 보다 직관적이다.
여러 개의 insert 구문을 만들 수 있는데 이를 구분하는 것이 id값
update, delete 등 다른 것도 마찬가지.
id값으로 구분하고, <mapper namespace="BoardDAO"> 의 namespace를통해 접근한다.
VO 객체를 통해 값을 가져오고, VO 객체를 통해 값을 돌려줘야 하는데 여기서는
resultType="” 이게 그 역할을 해준다.
데이터베이스 설정 정보도 만들어줘야 한다.
db.properties 파일 만들어서
jdbc.driver=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@localhost:1522:orcl1
jdbc.username=scott
jdbc.password=tiger
sql-map-config 에서는 DB 정보를 사용하기 위해 DB 정보가 담겨있는 db.properties 파일 연결해주기.
<properties resource="db.properties" />
sql-map-config 전문
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- Properties 파일 설정 -->
<properties resource="db.properties" />
<!-- Alias 설정 -->
<typeAliases>
<typeAlias alias="board"
type="com.springbook.biz.board.BoardVO" />
</typeAliases>
<!-- DataSource 설정, 트랜잭션 연결 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.dirver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- Sql Mapper 설정 -->
<mappers>
<mapper resource="mappings/board-mapping.xml" />
</mappers>
</configuration>
에서 <typeAlias alias="board" type="com.springbook.biz.board.boardVO"/>는 BoardVO를 가리킨다.
type="com.springbook.biz.board.boardVO" 을 지정해줌으로서
BoardVO를 board라고 명명하고
board-mapping.xml에서 BoardVO를 board라고 쓸 수 있게 해준다.
SQL 이랑 연결이 된다는 것이 직접적인 트렌잭션, 쿼리문 처리가 가능하다는 것.
SqlSessionFactoryBean.java
package com.springbook.biz.util;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class SqlSessionFactoryBean {
// SQL에 연결
// 싱글톤 패턴
// IO 스트림 관련 작업은 다 예외 처리 필요
private static SqlSessionFactory sessionFactory = null;
static {
try {
if (sessionFactory == null) {
Reader reader = Resources.getResourceAsReader("sql-map-config.xml");
sessionFactory = new SqlSessionFactoryBuilder().build(reader);
}
} catch (Exception e) {
e.printStackTrace();
}
}
// SqlSession 정보를 리턴 받으면 sql 정보를 쓸 수 있다.
public static SqlSession getSqlSessionInstance() {
return sessionFactory.openSession();
}
}
BoardDAO.java
package com.springbook.biz.board.impl;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import com.springbook.biz.board.BoardVO;
import com.springbook.biz.util.SqlSessionFactoryBean;
public class BoardDAO {
// SqlSession 타입 mybatis은 xml의 정보를 다 가지고 있다.
private SqlSession mybatis;
public BoardDAO() {
mybatis = SqlSessionFactoryBean.getSqlSessionInstance();
}
// 글 등록
public void insertBoard(BoardVO vo) {
mybatis.insert("BoardDAO.insertBoard", vo);
mybatis.commit();
}
// 글 수정
public void updateBoard(BoardVO vo) {
mybatis.update("BoardDAO.updateBoard", vo);
mybatis.commit();
}
// 글 삭제
public void deleteBoard(BoardVO vo) {
}
// 글 상세조회
public BoardVO getBoard(BoardVO vo) {
return null;
}
// 글 목록 조회
public List<BoardDAO> getBoardList(BoardVO vo) {
return null;
}
}
전체적인 파일 구조
일단 맥북에서
복습하며 json 형식으로 값을 받아와 목록을 만들었다.
페이징부터.. 이것저것 너무 할게 많다!
'2024_UIUX 국비 TIL' 카테고리의 다른 글
UIUX _국비과정 0729 ~ 30 (🍀Git, git bash 명령어) (0) | 2024.08.22 |
---|---|
UIUX _국비과정 0726 [🍀MyBatis] (0) | 2024.08.22 |
UIUX _국비과정 0724 [검색기능, 파일업로드, 제이슨 형식으로 반환받기] (0) | 2024.08.21 |
UIUX _국비과정 0723 [스프링 컨트롤러 사용하기] (0) | 2024.08.19 |
UIUX _국비과정 0722 [웹소켓 채팅, 스프링 컨트롤러 사용하기] (0) | 2024.07.31 |