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 형식으로 값을 받아와 목록을 만들었다.

 

페이징부터.. 이것저것 너무 할게 많다!

+ Recent posts