<리액트, pojo 파일첨부 추가 - BoardDetail.jsx>
import React, { useEffect, useState } from 'react'
import { json, useParams } from 'react-router-dom'
import { boardListDB } from '../../service/dbLogic'
import { ContainerDiv, FormDiv, HeaderDiv } from '../styles/FormStyle'
import BoardFileDetail from './BoardFileDetail'
import BoardHeader from './BoardHeader'
const BoardDetail = () => {
const {bm_no} = useParams()
console.log(bm_no)
const[pboard, setPBoard] = useState({
bm_no: bm_no,
})
// 하나: 파일명(bs_file), 둘: 파일크기(bs_size)
const[files, setFiles] = useState({
})
const[board, setBoard] = useState({
BM_NO: 0,
BM_TITLE: "",
BM_WRITER: "",
BM_CONTENT: "",
BM_PW: "",
BM_REG: "",
BM_GROUP: 0,
BM_POS: 0,
BM_STEP: 0,
BM_HIT: 0,
BS_FILE: "",
BS_SIZE: "",
})
useEffect (() => {
// 동기-기다림, 비동기- 기다리는동안 다른일 처리
const boardDetail = async() => {
const res = await boardListDB(pboard)
console.log(res)
const result = JSON.stringify(res.data)
const jsonDoc = JSON.parse(result)
setBoard({BM_NO: jsonDoc[0].BM_NO, BM_TITLE: jsonDoc[0].BM_TITLE, BM_WRITER: jsonDoc[0].BM_WRITER,
BM_CONTENT: jsonDoc[0].BM_CONTENT, BM_PW: jsonDoc[0].BM_PW, BM_REG: jsonDoc[0].BM_REG,
BM_GROUP: jsonDoc[0].BM_GROUP, BM_POS: jsonDoc[0].BM_POS, BM_STEP: jsonDoc[0].BM_STEP,
BM_HIT: jsonDoc[0].BM_HIT
})
// 첨부파일, quill editor 이미지 파일
setFiles([jsonDoc[0].BS_FILE, jsonDoc[0].BS_SIZE])
}
boardDetail()
}, [pboard]) // 의존성 배열에는 제목에 해당되는 bm_no가 변경될 때마다 새로 실행됨
// 빈 배열이면 최초 App이 렌더링될 때(리턴에있는 컴포넌트가 렌더링될때) 딱 한 번만 실행됨
// 의존성 배열을 적지 않으면 변경될때마다 새로 읽는다 - 초기화된다(유지x)
// 주의사항: boards와 같은 n개 로우를 갖는 변수명을 사용X! - 무한루프(리렌더링) -> 대신 setBoards를 쓸것
return (
<ContainerDiv>
<HeaderDiv>
<h3 style={{marginLeft:"10px"}}>계층형 게시판</h3>
</HeaderDiv>
<FormDiv>
<BoardHeader board={board} bm_no={bm_no}/>
<section style={{minHeight: '400px'}}>
{/* 오라클 서버에서 읽어온 BM_CONTENT 정보를 Quill Editor에 출력하는 코드 */}
<div dangerouslySetInnerHTML={{__html:board.BM_CONTENT}}></div>
</section>
<BoardFileDetail files={files} />
<hr style={{height:"2px"}}/>
</FormDiv>
</ContainerDiv>
)
}
export default BoardDetail
<리액트, pojo 파일첨부 추가 - BoardFileDetail.jsx>
import React from 'react';
import axios from 'axios';
import styled from 'styled-components';
const Dspan = styled.span`
padding: 2px 5px 2px 5px;
font-size: 14px;
cursor: pointer;
&:hover {
border-bottom: 1px solid gray;
}
`
const BoardFileDetail = ({files}) => {
console.log(files[0]);
const download = () => {
axios({
method: 'GET',
url: process.env.REACT_APP_CHAT_BANANA_IP+`board3/imageDownload.st3?imageName=${files[0]}`,
responseType: 'blob'
}).then(response =>{
const url = window.URL.createObjectURL(new Blob([response.data],
{ type: response.headers['content-type'] }));
const link = document.createElement('a');
link.href = url;
//link.setAttribute('download', 'img.jpg');
link.setAttribute('download', `${files[0]}`);
document.body.appendChild(link);
link.click();
})
}
return (
<div style={{display:'block', border:'1px solid lightGray', borderRadius:'10px', minHeight:'60px', padding:'5px'}}>
<div style={{textAlign:"left", padding: "2px 5px 2px 5px"}}>첨부파일</div>
{
<div>
<Dspan type='text' id='fileUpload'
onClick={download}
>
{files[0]}
</Dspan>
</div>
}
</div>
);
};
export default BoardFileDetail;
<리액트, pojo 파일첨부 추가 - HandlerMapping.java>
package com.pojo.step3;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
public class HandlerMapping {
static Logger logger = Logger.getLogger(HandlerMapping.class);
/***************************************
* @param upmu[](upmu[0]=업무명,폴더명 | upmu[1]=메소드명, 기능명, 페이지이름)
* @param request -> 1-1, 1-2와는 다르게 인터페이스를 implements하지 않는다
* @param response -> HttpServlet
* Q. 어디서 받아오는가?
* @return Object
* 테스트 -> http://localhost:9000/board3/boardList.st3
***************************************/
public static Object getController(String[] upmu, HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
logger.info(upmu[0]+", "+upmu[1]);
Controller3 controller = null;
String path = null;
Object obj = null;
ModelAndView mav = null;
// 게시판 구현
if("board3".equals(upmu[0])) {
controller = new Board3Controller();
// 게시글 전체 목록 -> html 화면 출력(text/html)
if("boardList".equals(upmu[1])) {
obj = controller.boardList(req, res);
// 리턴타입이 ModelAndView인 경우
if(obj instanceof ModelAndView) {
return (ModelAndView)obj;
}
// 리턴타입이 String인 경우
else if(obj instanceof String) {
return (String)obj;
}
}
// json 게시글 전체 목록 -> json 화면 출력(application/json)
else if("jsonBoardList".equals(upmu[1])) {
obj = controller.jsonBoardList(req, res);
// 리턴타입이 ModelAndView인 경우
if(obj instanceof ModelAndView) {
return (ModelAndView)obj;
}
// 리턴타입이 String인 경우
else if(obj instanceof String) {
return (String)obj;
}
}
// 글 입력 - 새글쓰기와 댓글쓰기
else if("boardInsert".equals(upmu[1])) {
obj = controller.boardInsert(req, res);
// 리턴타입이 String인 경우
if(obj instanceof String) {
return (String)obj;
}
}
// 이미지 업로드 - 리액트 quill editor 이미지 추가
else if("imageUpload".equals(upmu[1])) {
obj = controller.imageUpload(req, res);
logger.info("imageUpload 호출 => " + obj instanceof String);
// 리턴타입이 String인 경우
if(obj instanceof String) {
return (String)obj;
}
}
// 이미지 다운로드 - 리액트 quill editor 이미지 추가
else if("imageDownload".equals(upmu[1])) {
obj = controller.imageDownload(req, res);
logger.info("imageDownload 호출 => " + obj instanceof String);
// 리턴타입이 String인 경우
if(obj instanceof String) {
return (String)obj;
}
}
// 리액트 -
else if("imageGet".equals(upmu[1])) {
obj = controller.imageGet(req, res);
logger.info("imageGet 호출 => " + obj instanceof String);
// 리턴타입이 String인 경우
if(obj instanceof String) {
return (String)obj;
}
}
// 글 수정 - 첨부파일 수정 유무 고려하기
else if("boardUpdate".equals(upmu[1])) {
obj = controller.boardUpdate(req, res);
// 리턴타입이 String인 경우
if(obj instanceof String) {
return (String)obj;
}
}
// 글 삭제 - 첨부파일 삭제 유무 고려하기
else if("boardDelete".equals(upmu[1])) {
obj = controller.boardDelete(req, res);
// 리턴타입이 String인 경우
if(obj instanceof String) {
return (String)obj;
}
}
// 글 상세보기
else if("boardDetail".equals(upmu[1])) {
obj = controller.boardDetail(req, res);
// 리턴타입이 ModelAndView인 경우
if(obj instanceof ModelAndView) {
return (ModelAndView)obj;
}
// 리턴타입이 String인 경우
else if(obj instanceof String) {
return (String)obj;
}
}
} // end of 게시판 구현
// 인증 관리 구현
else if("auth".equals(upmu[0])) {
}
// 회원 관리 구현
else if("member".equals(upmu[0])) {
}
// 주문 관리 구현
else if("order".equals(upmu[0])) {
}
return obj;
}
}
<리액트, pojo 파일첨부 추가 - Controller3.java>
package com.pojo.step3;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// javascript기반의 UI API
// 리액트는 바닐라스크립트 + ES6(주요이슈-spread, module, arrow),ES7 + html 섞어쓰기
public interface Controller3 {
public Object jsonBoardList(HttpServletRequest req, HttpServletResponse res);
public Object boardList(HttpServletRequest req, HttpServletResponse res);
public Object boardDetail(HttpServletRequest req, HttpServletResponse res);
public Object imageUpload(HttpServletRequest req, HttpServletResponse res);
public Object imageDownload(HttpServletRequest req, HttpServletResponse res);
public Object imageGet(HttpServletRequest req, HttpServletResponse res);
public Object boardInsert(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException;
public Object boardUpdate(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException;
public Object boardDelete(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException;
}
<리액트, pojo 파일첨부 추가 - Board3Controller.java>
package com.pojo.step3;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import com.oreilly.servlet.MultipartRequest;
import com.oreilly.servlet.multipart.DefaultFileRenamePolicy;
import com.util.HashMapBinder;
public class Board3Controller implements Controller3 {
Logger logger = Logger.getLogger(Board3Controller.class);
Board3Logic boardLogic = new Board3Logic();
// 메소드
@Override
public ModelAndView boardList(HttpServletRequest req, HttpServletResponse res) {
logger.info("boardList 호출");
List<Map<String, Object>> bList = null;
// 사용자가 조건 검색을 원하는 경우 - 조건 값을 전달할 객체 생성함
// MyBatis에서는 동적쿼리를 지원하므로 하나로 2가지 경우 사용 가능함
Map<String, Object> pMap = new HashMap<>();
HashMapBinder hmb = new HashMapBinder(req);
hmb.bind(pMap);
bList = boardLogic.boardList(pMap);
ModelAndView mav = new ModelAndView(req);
mav.setViewName("board3/boardList");
mav.addObject("bList", bList);
return mav; // 리턴이 mav면 webapp/WEB-INF/views/board3 아래의 jsp
}
@Override
public Object jsonBoardList(HttpServletRequest req, HttpServletResponse res) {
logger.info("jsonBoardList호출");
List<Map<String, Object>> bList = null;
Map<String, Object> pMap = new HashMap<>();
HashMapBinder hmb = new HashMapBinder(req);
hmb.bind(pMap);
bList = boardLogic.boardList(pMap);
// 오라클 연동 후에 조회 결과가 bList에 담겨있음
// forward할 때 그 주소번지를 저장해둠 - 화면(jsonBoardList.jsp)에서 접근함 - 키값이 중요함
req.setAttribute("bList", bList);
return "forward:board3/jsonBoardList"; // 리턴이 String이면 webapp/board3 아래의 jsp
}
@Override
public Object boardDetail(HttpServletRequest req, HttpServletResponse res) {
logger.info("boardDetail호출");
List<Map<String, Object>> bList = null;
// 전체 조회에 대한 sql문 재사용 가능함 - 1건 조회 경우
// 하지만 재사용성(상세보기 조회수 업데이트)를 위해 Logic의 메소드 나눔
Map<String, Object> pMap = new HashMap<>();
HashMapBinder hmb = new HashMapBinder(req);
hmb.bind(pMap);
bList = boardLogic.boardDetailList(pMap);
logger.info(bList);
req.setAttribute("bList", bList);
return "forward:board3/boardDetail";
}
/*
* INSERT INTO board_master_t(bm_no, bm_title, bm_writer, bm_content, bm_reg,
* bm_hit) VALUES(seq_board_no.nextval, #{bm_title}, #{bm_writer},
* to_char(sysdate, 'YYYY-MM-DD') ,
* )
*
* 화면에서 받아올 값 - bm_title, bm_writer, bm_content 그렇지 않은 경우 - bm_reg
*/
@Override
public Object boardInsert(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
logger.info("boardInsert호출");
int result = 0;
// 폼태그 안에 사용자가 입력한 정보(bm_writer, bm_title, bm_content...)를 받아온다
// req.getParameter("bm_writer")
// req.getParameter("bm_title")
// req.getParameter("bm_content")
// -> 계속 반복해야하기에 HashMapBinder클래스 공통코드 생성
Map<String, Object> pMap = new HashMap<>();
logger.info("before ==> " + pMap);
HashMapBinder hmb = new HashMapBinder(req);
hmb.multiBind(pMap);
logger.info("after ==> " + pMap);
result = boardLogic.boardInsert(pMap);
String path = "";
if (result == 1) {
path = "redirect:/board3/boardList.st3";
} else {
path = "redirect:/board3/boardInsertFail";
res.sendRedirect(path);
}
return path;
}
@Override
public Object boardUpdate(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
logger.info("boardUpdate호출");
int result = 0;
Map<String, Object> pMap = new HashMap<>();
HashMapBinder hmb = new HashMapBinder(req);
hmb.bind(pMap);
logger.info(pMap);
// result값의 변화를 주는 코드(0->1)
result = boardLogic.boardUpdate(pMap);
String path = "";
if (result == 1) {
path = "redirect:/board3/boardList.st3";
} else {
path = "redirect:/board3/boardUpdateFail";
res.sendRedirect(path);
}
return path;
}
@Override
public Object boardDelete(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
logger.info("boardDelete호출");
int result = 0;
Map<String, Object> pMap = new HashMap<>();
HashMapBinder hmb = new HashMapBinder(req);
hmb.bind(pMap);
result = boardLogic.boardDelete(pMap);
String path = "";
if (result == 1) {
path = "redirect:/board3/boardList.st3";
} else {
path = "redirect:/board3/boardUpdateFail";
res.sendRedirect(path);
}
return path;
}
// quill editor에서 이미지 선택하면 업로드처리 - 물리적인 위치 - 톰캣서버 - chat_banana - webapp - pds
// 첨부파일 업로드 API는 cos.jar 사용 - maven repo
// 하나. 바이너리 타입 코드 첨부할 때
// 둘. 이미지 파일 첨부할 때
// 첨부파일 처리(application[main타입]/*[sub타입-img.png, img.gif]
// 파일크기 제한 5MB - 유효성 체크 필요(UI에서 체크해서 5MB 초과시 에러화면 처리)
@Override
public Object imageUpload(HttpServletRequest req, HttpServletResponse res) {
logger.info("imageUpload 호출 성공");
// 첨부파일 처리에 필요한 변수 선언
// get방식 - header에 담김 - query string
// post방식 - encType속성 - request.getParameter("") 사용자가 입력한 값을 읽을 수 없음
MultipartRequest multi = null; // post이면서 첨부파일이 있는 형태인 경우 이 클래스가 반드시 필요함
String realFolder = "D:\\workspace_java\\chat_banana\\src\\main\\webapp\\pds";
// 첨부파일의 한글처리
String encType = "utf-8";
// 첨부파일의 크기
int maxSize = 50 * 1024 * 1024; // 5MB
try {
// 인스턴스화하기 - 인스턴스화가 성공하자마자 pds폴더에 추가됨
// @param1 - req 요청 - body에 담김(post방식) - 단위테스트x
// @param2 - 실제 파일이 있는 물리적인 위치
// @param3 - 첨부파일의 최대 크기값
// @param4 - 한글 인코딩 설정값
// @param5 - 같은 이름이 있을 경우 관찰하고 그에대한 대응값 반환
multi = new MultipartRequest(req, realFolder, maxSize, encType, new DefaultFileRenamePolicy());
// 거의 즉시 업로드됨 - 파일 크기가 크면 지연상태에 빠짐 - dead lock로 상태 이어지지 않도록 조심!
} catch (Exception e) {
logger.info("Exception : " + e.toString());
}
// String filename = boardLogic.imageUpload(multi, realFolder);
Map<String, Object> rMap = boardLogic.imageUpload(multi, realFolder);
logger.info(rMap);
// Gson g = new Gson();
// String temp = g.toJson(rMap);
// logger.info(temp);
// logger.info(g);
String temp = "";
temp = rMap.get("bs_file").toString() + "," + rMap.get("bs_size").toString();
logger.info(temp);
return temp;
}
// process.env.REACT_APP_CHAT_BANANA_IP+`board3/imageGet.st3?imageName=${res.data}`
// Quill Editor에서 필요 - 위지웤기능 첨가 <p></p><img... /> PNG, JPG, JPEG
// 일단 이미지를 선택하면 pds에 먼저 업로드되고, 그 이미지 경로를 참조해서 editor에 출력해줌
// 리턴타입이 널인 이유는 이미지 정보를 얻어오는 것이기에 -> 화면적으로 처리할 부분이 없다
// 에디터에서 이미지를 선택하면 bm_content 컬럼에 img태그와 함께 이미지 정보에대한 소스가
// 텍스트 형태로 저장됨
// 오라클 서버에 저장된 bm_content내용을 읽어서 브라우저에 출력해줌
@Override
public Object imageGet(HttpServletRequest req, HttpServletResponse res) {
// imageName 정보는 공통코드로 제공된 QuillEditor.jsx에서 파라미터로 넘어오는 값임
// imageUpload 메소드에서는 업로드된 파일 정보(파일명, 파일크기)가 리턴됨
String b_file = req.getParameter("imageName"); // get방식으로 넘어옴
logger.info("imageGet 호출 성공===>" + b_file); // XXX.png
// 톰캣 서버의 물리적인 위지 정보
String filePath = "D:\\workspace_java\\chat_banana\\src\\main\\webapp\\pds"; // 절대경로.
String fname = b_file;
logger.info("b_file: 8->euc" + b_file);
// File은 내용까지 복제되는 것은 아니고 파일명만 객체화해주는 클래스이다
File file = new File(filePath, b_file.trim());
// 실제 업로드된 파일에 대한 마임타입을 출력해줌
String mimeType = req.getServletContext().getMimeType(file.toString());
logger.info(mimeType); // image, video, text
if (mimeType == null) { // 마임타입이 널이면 아래의 속성값으로 마임타입을 설정
// -> 브라우저는 해석이 가능한 마임타입은 페이지 로딩 처리,
// 해석이 불가능한 마임타입은 다운로드함
// 강제로 다운로드 처리를 위한 마임타입 변경
// -> 브라우저에서 해석가능한 마임타입의 경우 화면에 그대로 출력되니까 그걸 방지하기위해
res.setContentType("application/octet-stream");
}
// 다운로드되는 파일 이름 담기
String downName = null;
// 위 File 객체에서 생성된 객체에 내용을 읽기위한 클래스 선언
FileInputStream fis = null;
// 응답으로 나갈 정보가 웹 서비스에 처리되어야 하기에 사용한 객체
ServletOutputStream sos = null;
try {
if (req.getHeader("user-agent").indexOf("MSIE") == -1) {
downName = new String(b_file.getBytes("UTF-8"), "8859_1");
} else {
downName = new String(b_file.getBytes("EUC-KR"), "8859_1");
}
// 응답 헤더에 다운로드 될 파읿명을 매핑하기
res.setHeader("Content-Disposition", "attachment;filename=" + downName);
// 위에서 생성된 파일 문자열 객체를 가지고 파일생성에 필요한 객체의 파라미터 넘김
fis = new FileInputStream(file);
sos = res.getOutputStream();
// 파일 내용을 담을 byte배열을 생성
byte b[] = new byte[1024 * 10];
int data = 0;
while ((data = (fis.read(b, 0, b.length))) != -1) {
// 파일에서 읽은 내용을 가지고 실제 파일에 쓰기 처리함
// 여기서 처리된 값은 브라우저를 통해서 내보내진다
sos.write(b, 0, data);
}
// 처리한 내용이 버퍼에 있는데 이것을 모두 처리요청하기
// 내보내고 버퍼를 비운다 - 버퍼는 크기가 작음(휘발성)
sos.flush();
} catch (Exception e) {
logger.info(e.toString());
} finally {
try {
if (sos != null)
sos.close();
if (fis != null)
fis.close();
} catch (Exception e2) {
// TODO: handle exception
}
}
// byte[] fileArray = boardLogic.imageDownload(imageName);
// logger.info(fileArray.length);
return null;
}// end of imageGet
/**
* 이미지 다운로드
*
* @param req
* @param res
*/
// download.jsp 페이지의 내용과 같다
@Override
public Object imageDownload(HttpServletRequest req, HttpServletResponse res) {
logger.info("imageDownload 호출 성공");
String b_file = req.getParameter("imageName");
String filePath = "D:\\workspace_java\\chat_banana\\src\\main\\webapp\\pds"; // 절대경로.
String fname = b_file;
logger.info("b_file: 8->euc"+b_file);
File file = new File(filePath,b_file.trim());
String mimeType = req.getServletContext().getMimeType(file.toString());
logger.info("mimeType : "+mimeType);
if(mimeType == null){
res.setContentType("application/octet-stream");
}
String downName = null;
FileInputStream fis = null;
ServletOutputStream sos = null;
try{
if(req.getHeader("user-agent").indexOf("MSIE")==-1){
downName = new String(b_file.getBytes("UTF-8"),"8859_1");
}else{
downName = new String(b_file.getBytes("EUC-KR"),"8859_1");
}
res.setHeader("Content-Disposition", "attachment;filename="+downName);
fis = new FileInputStream(file);
sos = res.getOutputStream();
byte b[] = new byte[1024*10];
int data = 0;
while((data=(fis.read(b,0,b.length)))!=-1){
sos.write(b,0,data);
}
sos.flush();
}catch(Exception e){
logger.info(e.toString());
}finally{
try {
if(sos != null) sos.close();
if(fis != null) fis.close();
} catch (Exception e2) {
// TODO: handle exception
}
}
return null;
}// end of imageDownload
}
<리액트, pojo 파일첨부 추가 - PageBar.java>
package com.util;
import org.apache.log4j.Logger;
public class PageBar {
Logger logger = Logger.getLogger(PageBar.class);
//전체레코드 갯수
private int totalRecord;//list.size():47row
//페이지당 레코드 수
private int numPerPage;// 10개씩이다
//블럭당 디폴트 페이지 수 - 여기서는 일단 3개로 정함.
private int pagePerBlock=3;
//총페이지 수
private int totalPage;
//총블럭 수
private int totalBlock;
//현재 내가 바라보는 페이지 수
private int nowPage;
//현재 내가 바라보는 블럭 수
private int nowBlock;
//적용할 페이지 이름
private String pagePath;
private String pagination;
//페이지 네비게이션 초기화
/*
* 화면에서 받아와야 하는 정보에는 어떤 것들이 있을까?
* 페이지에 뿌려질 로우의 수 numberPerPage
* 전체 레코드 수 totalRecord
* 현재 내가 바라보는 페이지 번호 nowPage
* 내가 처리해야할 페이지 이름 pagePath
*
* 공식을 세우는데 필요한 인자는 누구?
*
* 세워진 공식들은 어디에서 적용하면 되는 거지?
*
* 화면에 내보내 져야 하는 언어는 html 아님 자바 중에서 ?????
* html
* 내보내지는 정보는 어디에 담으면 될까?
*
*/
public PageBar(int numPerPage, int totalRecord, int nowPage, String pagePath) {
this.numPerPage = numPerPage;
this.totalRecord = totalRecord;
this.nowPage = nowPage;
this.pagePath = pagePath;
this.totalPage =
(int)Math.ceil((double)this.totalRecord/this.numPerPage);// 47.0/10=> 4.7 4.1->5page 4.2->5page
this.totalBlock=
(int)Math.ceil((double)this.totalPage/this.pagePerBlock);//5.0/2=> 2.5-> 3장
//현재 내가바라보는 페이지 : (int)((double)4-1/2)
this.nowBlock = (int)((double)this.nowPage/this.pagePerBlock);
}
//setter메소드 선언
public void setPageBar() {
StringBuilder pageLink = new StringBuilder();
//전체 레코드 수가 0보다 클때 처리하기
if(totalRecord>0) {
//nowBlock이 0보다 클때 처리
//이전 페이지로 이동 해야 하므로 페이지 번호에 a태그를 붙여야 하고
//pagePath뒤에 이동할 페이지 번호를 붙여서 호출 해야함.
if(nowBlock > 0 ) { //(1-1)*2+(2-1)=1
pageLink.append("<a href='"+pagePath+"?nowPage="+((nowBlock-1)*pagePerBlock+(pagePerBlock-1))+"'>");
pageLink.append("<img border=0 src='/images/bu_a.gif'>");
pageLink.append("</a> ");
}
for(int i=0;i<pagePerBlock;i++) {
//현재 내가 보고 있는 페이지 블록 일때와
if(nowBlock*pagePerBlock+i==nowPage) {
pageLink.append("<b>"+(nowBlock*pagePerBlock+i+1)+"</b> ");
}
//그렇지 않을 때를 나누어 처리해야 함.
else {
pageLink.append("<a href='"+pagePath+"?nowPage="+((nowBlock*pagePerBlock)+i)+"'>"+((nowBlock*pagePerBlock)+i+1)+"</a> ");
}
//모든 경우에 pagePerBlock만큼 반복되지 않으므로 break처리해야 함.
//주의할 것.
if((nowBlock*pagePerBlock)+i+1==totalPage) break;
}
//현재 블록에서 다음 블록이 존재할 경우 이미지 추가하고 페이지 이동할 수 있도록
//a태그 활용하여 링크 처리하기
if(totalBlock > nowBlock+1) {
pageLink.append(" <a href='"+pagePath+"?nowPage="+((nowBlock+1)*pagePerBlock)+"'>");
pageLink.append("<img border=0 src='/images/bu_b.gif'>");
pageLink.append("</a>");
}
}
logger.info("pageLink.toString():"+pageLink.toString());
pagination = pageLink.toString();
}
//getter메소드 선언
public String getPageBar() {
this.setPageBar();
return pagination;
}
}
<리액트, pojo 파일첨부 추가 - boardList.jsp>
<%@page import="com.util.PageBar"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.util.*, com.util.PageBar" %>
<%
// jsp에서 자바코드(스크립틀릿)와 html코드의 작성 위치는 문제가 되지 않는다.
// 왜냐하면 어차피 jsp는 서버에서 실행되고 그 결과가 text로 출력되는 것이므로
// html과 처리 시점이 완전 다르니까...
List<Map<String,Object>> boardList =
(List<Map<String,Object>>)request.getAttribute("bList");
int size = 0;
if(boardList!=null){
size = boardList.size();
}
// 한 페이지에 출력될 로우의 수
int numPerPage = 3;
// 현재 내가 바라보는 페이지
int nowPage = 0;
if(request.getParameter("nowPage") != null){
nowPage = Integer.parseInt(request.getParameter("nowPage"));
}
%>
<!DOCTYPE html>
<html>
<head>
<!-- <meta charset="UTF-8"> 이것때문에 한글깨짐.-->
<title>MVC기반의 계층형 게시판 구현하기[WEB-INF]</title>
<%@ include file="../common/easyUI_common.jsp" %>
<script type="text/javascript">
let g_no=0;//그리드에서 선택이 바뀔때 마다 변경된 값이 저장됨.
let tb_value;//사용자가 입력한 문자열 담기
let isOk = false;
function dlgIns_save(){
//폼 전송 처리함.
$("#f_boardIns").submit();
}
function dlgIns_close(){
$("#dlg_boardIns").dialog('close');
}
function getBoardList(){
//alert("getBoardList호출");
//사용자가 선택한 콤보박스에 value가 담김 - b_title, or b_content or b_writer
cb_value = user_combo;
tb_value = $("#tb_search").val();//사용자가 입력한 조건 검색 문자열
console.log("콤보박스 값: "+ cb_value+", 사용자가 입력한 키워드: "+tb_value);
location.href = "./boardList.st3?cb_search="+cb_value+"&tb_search="+tb_value+"&bm_reg="+v_date;
}
function boardDetail(bm_no){
console.log(bm_no)
location.href = "./boardDetail.st3?bm_no="+bm_no;
}
function fileDown(fname){
location.href="downLoad.jsp?bs_file="+fname;
}
</script>
</head>
<body>
<script type="text/javascript">
let user_combo="bm_title";//제목|내용|작성자
//전변 - javascript에서는 선언만 하고 선택을 하지 않았거나 값이 할당되지 않으면
//그냥 null비교만 해서는 안된다.
let v_date;//사용자가 선택한 날짜 정보 담기
//기본 날짜포맷을 재정의
$.fn.datebox.defaults.formatter = function(date){
var y = date.getFullYear();
var m = date.getMonth()+1;
var d = date.getDate();
return y+'-'+(m<10? "0"+m:m)+'-'+(d<10? "0"+d:d);
}
//날짜 포맷을 적용
$.fn.datebox.defaults.parser = function(s){
var t = Date.parse(s);
if (!isNaN(t)){
return new Date(t);
} else {
return new Date();
}
}
$(document).ready(function(){//DOM구성이 완료된 시점-자바스크립트로 태그접근,설정변경,이미지
$("#dg_board").datagrid({
onSelect:function(index,row){
g_no = row.B_NO;
console.log("g_no:"+g_no);
},
onDblClickCell: function(index, field, value){
if("B_TITLE" == field){
location.href="./boardDetail.pj?b_no="+g_no;
g_no = 0;
$("#dg_board").datagrid('clearSelections')
}
}
});
//등록 날짜 정보를 선택했을 때
$('#db_date').datebox({
//왜? undefinded이었나?
onSelect: function(date){
//alert(date.getFullYear()+":"+(date.getMonth()+1)+":"+date.getDate());
const y = date.getFullYear();
const m = date.getMonth()+1;
const d = date.getDate();
v_date = y+"-"+(m<10? "0"+m:m)+"-"+(d<10? "0"+d:d);
//console.log("사용자가 선택한 날짜 ==> "+v_date);
}
});
//검색 조건 콤보에 변경이 일어났을 때
$('#cb_search').combobox({
onChange:function(){
user_combo = $("#cb_search").combobox('getValue');//b_title or b_content or b_writer
console.log(user_combo)
}
});
$('#tb_search').textbox({
icons: [{
iconCls:'icon-search',
handler: function(e){
console.log("검색");
//$(e.data.target).textbox('setValue', 'Something added!');
$("#dg_board").datagrid({
});
}
}]
});
/*===================== CRUD버튼 시작 ====================*/
//조회버튼 클릭했을 때
$('#crudBtnSel').bind('click', function(){
getBoardList();
});
$('#crudBtnIns').bind('click', function(){
//alert('입력 버튼');
$("#dlg_boardIns").dialog('open');
});
$('#crudBtnUpd').bind('click', function(){
alert('수정 버튼');
});
$('#crudBtnDel').bind('click', function(){
alert('삭제 버튼');
});
/*===================== CRUD버튼 끝 ====================*/
});///////////////// end of ready
</script>
<center>
<table id="dg_board" class="easyui-datagrid" title="계층형 게시판 목록" style="width:800px;height:550px"
data-options="rownumbers:true,singleSelect:true,toolbar:'#tb',footer:'#pn_board'">
<thead>
<tr>
<th data-options="field:'BM_NO',width:60, align:'center', hidden:'true'">글번호</th>
<th data-options="field:'BM_TITLE',width:350">제목</th>
<th data-options="field:'BM_WRITER',width:80,align:'center'">작성자</th>
<th data-options="field:'BM_REG',width:100,align:'center'">작성일</th>
<th data-options="field:'BS_FILE',width:170">첨부파일</th>
<th data-options="field:'BM_HIT',width:60,align:'center'">조회수</th>
</tr>
</thead>
<tbody>
<%
if(size==0){
%>
<script>
$.messager.alert('Info','조회결과가 없습니다.');
</script>
<%
}
else if(size>0){
for(int i = nowPage*numPerPage; i < (nowPage*numPerPage)+numPerPage; i++){
if(size == i) break;
Map<String,Object> rMap = boardList.get(i);
%>
<tr>
<td><%=1%></td>
<td>
<!-- 너 댓글이니? -->
<%
String imgPath = path + "..\\images\\";
if(Integer.parseInt(rMap.get("BM_POS").toString()) > 0){
for(int j=0; j<Integer.parseInt(rMap.get("BM_POS").toString()); j++){
out.print(" ");
}
%>
<img src="<%=imgPath%>reply.gif" />
<%
}
%>
<a href="javascript:boardDetail('<%=rMap.get("BM_NO") %>')" style="text-decoration:none;color:#000000">
<%=rMap.get("BM_TITLE")%>
</a>
</td>
<td><%=rMap.get("BM_WRITER")%></td>
<td><%=rMap.get("BM_REG")%></td>
<td>
<a href="javascript:fileDown('<%=rMap.get("BS_FILE")%>')" style="text-decoration: none; color:#000000">
<%=rMap.get("BS_FILE")%>
</a>
</td>
<td><%=rMap.get("BM_HIT")%></td>
</tr>
<%
}// end of for
}// end of else if
%>
</tbody>
</table>
<!-- 툴바 추가 중 조건검색 화면 시작 -->
<div id="tb" style="padding:2px 5px;">
<!--
req.getParameter("cb_search"):String
SELECT * FROM board_master_t
WHERE ?(컬럼) LIKE %||?||%
-->
<select class="easyui-combobox" id="cb_search" name="cb_search" panelHeight="auto" style="width:100px">
<option selected>선택</option>
<option value="bm_title">제목</option>
<option value="bm_content">내용</option>
<option value="bm_writer">작성자</option>
</select>
<input id="tb_search" name="tb_search" class="easyui-textbox" style="width:320px">
작성일: <input id="db_date" class="easyui-datebox" name="bm_date" style="width:110px">
<!-- 버튼 추가 화면 시작 -->
<div id="ft" style="padding:2px 5px;">
<a id="crudBtnSel" href="#" class="easyui-linkbutton" iconCls="icon-search" plain="true">조회</a>
<a id="crudBtnIns" href="#" class="easyui-linkbutton" iconCls="icon-edit" plain="true">입력</a>
<a id="crudBtnUpd" href="#" class="easyui-linkbutton" iconCls="icon-reload" plain="true">수정</a>
<a id="crudBtnDel" href="#" class="easyui-linkbutton" iconCls="icon-cut" plain="true">삭제</a>
</div>
<!-- 버튼 추가 화면 끝 -->
</div>
<!-- 툴바 추가 중 조건검색 화면 끝 -->
<!-- 페이지 네이션 추가 시작 -->
<div style="display:table-cell;vertical-align:middle; width:800px; background:#efefef; height:30; border:1px solid #ccc;">
<%
// 페이지 네비게이션이 필요한 페이지가 다를 것이다
String pagePath = "boardList.st3";
// 인스턴스화 할 때 생성자 파라미터로 페이징 처리에 필요한 변수 초기화
// 페이징 처리에 필요한 a태그들에 대한 문자열을 만들어서 getPageBar() 메소드를 호출하면
// 페이징 처리에 필요한 문자열을 stringBuilder에 처리하였고
// 그 문자열을 toString()으로 읽어와서 출력해줌
PageBar pb = new PageBar(numPerPage, size, nowPage, pagePath);
out.print(pb.getPageBar());
%>
</div>
<!-- 페이지 네이션 추가 끝 -->
<%
String gubun = request.getParameter("gubun");
if("list".equals(gubun)){
%>
<script type="text/javascript">
getBoardList();
</script>
<%
}
%>
<!-- 글입력 화면 추가 시작 -->
<div id="dlg_boardIns" footer="#tb_boardIns" class="easyui-dialog" title="글쓰기" data-options="modal:true,closed:true" style="width:600px;height:400px;padding:10px">
<form id="f_boardIns" method="post" enctype="multipart/form-data" action="./boardInsert.st3">
<!-- <form id="f_boardIns" method="get" action="./boardInsert.st3"> -->
<!--
hidden속성은 화면에 보이지 않음 - 개발자가 필요로하는 값
등록 부분과 수정 부분이 동시에 발생할 수도 있다 - 트랜젝션 처리가 필요함
트랜잭션 처리가 필요한 경우의 메소드 설계
-->
<input type="hidden" id="bm_no" name="bm_no" value="0">
<input type="hidden" id="bm_group" name="bm_group" value="0">
<input type="hidden" id="bm_pos" name="bm_pos" value="0">
<input type="hidden" id="bm_step" name="bm_step" value="0">
<table>
<tr>
<td width="100px">제 목</td>
<td width="500px"><input id="bm_title" name="bm_title" class="easyui-textbox" data-options="width:'250px'" required></td>
</tr>
<tr>
<td width="100px">작 성 자</td>
<td width="500px"><input id="bm_writer" name="bm_writer" class="easyui-textbox" data-options="width:'150px'" required></td>
</tr>
<tr>
<td width="100px">내 용</td>
<td width="500px"><input id="bm_content" name="bm_content" class="easyui-textbox" data-options="multiline:'true',width:'350px', height:'90px'" required></td>
</tr>
<tr>
<td width="100px">비 번</td>
<td width="500px"><input id="bm_pw" name="bm_pw" class="easyui-textbox" data-options="width:'100px'" required></td>
</tr>
<tr>
<td width="100px">첨부파일</td>
<td width="500px"><input id="bs_file" name="bs_file" class="easyui-filebox" data-options="width:'350px'"></td>
</tr>
</table>
</form>
</div>
<!-- 다이얼로그 화면 버튼 추가 시작 -->
<div id="tb_boardIns">
<a href="javascript:dlgIns_save()" class="easyui-linkbutton">저장</a>
<a href="javascript:dlgIns_close()" class="easyui-linkbutton">닫기</a>
</div>
<!-- 다이얼로그 화면 버튼 추가 끝 -->
<!-- 글입력 화면 추가 끝 -->
</center>
</body>
</html>
<스프링 맵 - InsaMap.java>
package com.example.demo.di;
import java.util.HashMap;
public class InsaMap {
HashMap<String, String> insaMap = null;
// 생성자 객체주입법 코드와 setter 객체주입법 코드가 있다
// spring boot에서는 @Autowired 어노테이션으로 필요가 없어짐
// insaMap = new HashMap<>();를 대신 해줌
// setter 객체 주입법
public void setInsaMap(HashMap<String, String> insaMap) {
this.insaMap = insaMap;
}
}
<스프링 맵 - InsaMap.xml>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="insaMap" class="com.example.demo.di.InsaMap">
<property name="insaMap">
<map>
<entry>
<key><value>one</value></key>
<value>Hi!</value>
</entry>
<entry>
<key><value>two</value></key>
<value>Have a good time</value>
</entry>
<entry>
<key><value>three</value></key>
<value>Have a nice day</value>
</entry>
</map>
</property>
</bean>
</beans>
<스프링 맵 - InsaMain.java>
package com.example.demo.di;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class InsaMain {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("com\\example\\demo\\di\\insaMap.xml");
InsaMap insaMap = (InsaMap)context.getBean("insaMap");
System.out.println(insaMap.insaMap);
// {one=Hi!, two=Have a good time, three=Have a nice day}
}
}
STS 실행 시 톰캣 못 찾아서 jsp 다운로드될 경우 아래코드 추가하고 spring-boot-starter-tomcat 삭제할 것!
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-jasper -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
pojo와 스프링비교
서블릿 등록하기
web.xml - 배치서술자(deployment descriptor) → pojo
@WebServlet(”XXX.do”) → 스프링
웹서비스-http, request, response → 서블릿 제공
request.getParameter(”mem_id”); → 반복코드(파라미터만 다름, <input>에 사용자가 입력한 값)
request.getParameter(”mem_pw”);
request.getParameter(”mem_name”);
pojo3부터 HashMapBinder.java 사용 → 반복되는 코드를 줄임
스프링→@RequestParam Map(타입)
서블릿
FrontMVC1 → ActionServlet → ActionSupport(pojo1~3)
서블릿에 의존적인 프레임워크(req, res 없이는 페이지이동 x)
요청객체와 응답객체가 있어야 듣기와 말하기가 가능함
req.getParameter() → Servlet필요(web.xml에 등록)
→ 요청객체와 응답객체가 없어도 웹서비스 가능했으면..
DispatcherServlet
spring에서 제공하는 서블릿 → 3.0까지
web.xml에 등록
4.0부터는 완전한 독립이 가능(서블릿으로부터의 완전한 독립)
@Controller → 화면 출력용
@RestController → 데이터셋 출력용(리턴타입 String, 마임타입 text/plain)
더 이상 web.xml 필요하지 않음
완전 자동화
컨트롤계층-연결만 담당, 응답페이지 결정
forward:board/boardList → application.properties에 prefix, suffix 설정해 뒀기에 뒤에 .jsp 붙이지 않음, scope는 request
redirect:board/boardList → scope는 page
둘 다 없는 것 → ModelAndView(이제 안 씀) → Model, ModelMap(어노테이션 아님, 파라미터로 객체 주입받음, UI패키지 제공, 화면처리용)
void doGet() or doPost()
→ void doService(): 오버라이딩 아님
→ ActionForward execute(req, res): 오버라이딩
→ String execute(req, res): 오버라이딩
→ String 메소드이름변함(req, res): 일반 메소드도 req, res 가지게 됨, XXXController가 더 이상 서블릿이 아니다
<테스트 시나리오>
1. board/boardList.jsp
위와 같이 테스트하는 것은 컨트롤 클래스를 경유하지 않음
webapp폴더 아래 board 아래에 있는 boardList.jsp 페이지를 요청하는 것임
2. board/boardList
컨트롤 클래스를 경유함
응답 페이지를 webapp에서 찾을지 혹은 WEB-INF/views/ 아래에서 찾을지 아직은 결정할 수 없는 상태임
return “forward:board/boardList”
return “redirect:board/boardList”
return “board/boardList”
Spring Boot 어노테이션
자바에서 Annotation(@)은 코드 사이에 주석처럼 쓰이며 특별한 의미, 기능을 수행하도록 하는 기술
프로그램에 추가적인 정보를 제공해 주는 메타데이터
@Controller
Spring에게 해당 Class가 Controller의 역할을 한다고 명시하기 위해 사용
view(화면) 리턴이 주목적
@RestController
Controller 중 View로 응답하지 않는 Controller를 의미
method의 반환 결과를 JSON 형태로 반환함
view가 필요 없는 API만 지원하는 서비스에서 사용
data(json, xml 등) 리턴이 주목적
@Service
Service Class에서 쓰임
비즈니스 로직을 수행하는 클래스라는 것을 나타내는 용도
@Repository
Dao Class에서 쓰임 DB에 접근하는 메소드를 가지고 있는 클래스에서 쓰임
@RequestMapping
@RequestMapping(value=”“)와 같은 형태로 작성
요청 들어온 URI의 요청과 Annotation value 값이 일치하면 해당 클래스나 메소드가 실행
요청받는 형식을 정의하지 않으면 GET으로 자동 설정됨
@GetMapping
RequestMapping(Method=RequestMethod.GET)과 똑같은 역할
@Autowired
Bean을 주입받기 위하여 사용
스프링이 자동적으로 값을 할당해 줌
→ Bean을 주입받는 방식: @Autowired, setter, 생성자
<스프링부트 - application.properties>
server.port=8000
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
<스프링부트 - BoardController.java>
package com.example.demo.controller;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.example.demo.logic.BoardLogic;
@Controller
@RequestMapping("/board/*")
public class BoardController {
Logger logger = LoggerFactory.getLogger(BoardController.class);
@Autowired
private BoardLogic boardLogic = null;
// setter없이 @Autowired만으로 의존성 주입 가능
@GetMapping("boardList")
public String boardList(Model model, @RequestParam Map<String, Object> pMap) {
logger.info("boardList 호출");
logger.info(pMap.toString());
List<Map<String, Object>> bList = null;
bList = boardLogic.boardList(pMap);
model.addAttribute("bList", bList);
// return "forward:boardList.jsp"; -> webapp 연결
return "board/boardList"; // WEB-INF 연결(application.properties에 설정해둠)
}
}
<스프링부트 - RestBoardController.java>
package com.example.demo.controller;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.logic.BoardLogic;
import com.google.gson.Gson;
@RestController
@RequestMapping("/board/*")
public class RestBoardController {
Logger logger = LoggerFactory.getLogger(RestBoardController.class);
@Autowired
private BoardLogic boardLogic = null;
// setter없이 @Autowired만으로 의존성 주입 가능
@GetMapping("jsonBoardList")
public String boardList(Model model, @RequestParam Map<String, Object> pMap) {
logger.info("jsonBoardList 호출");
logger.info(pMap.toString());
List<Map<String, Object>> bList = null;
bList = boardLogic.boardList(pMap);
model.addAttribute("bList", bList);
Gson g = new Gson();
String temp = g.toJson(bList);
return temp;
}
@GetMapping("getTest")
public String getTest () {
logger.info("getTest 호출");
return "테스트";
}
}
<스프링부트 -BoardLogic.java>
package com.example.demo.logic;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.demo.dao.BoardDao;
@Service
public class BoardLogic {
Logger logger = LoggerFactory.getLogger(BoardLogic.class);
@Autowired
private BoardDao boardDao = null;
public List<Map<String, Object>> boardList(Map<String, Object> pMap) {
logger.info("boardList 호출");
List<Map<String, Object>> bList = new ArrayList<>(); // NullPointerException 회피
bList = boardDao.boardList(pMap);
return bList;
}
}
<스프링부트 -BoardDao.java>
package com.example.demo.dao;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
// @Repository -> MVC패턴 학습위해 Service로 처리
@Service
public class BoardDao {
Logger logger = LoggerFactory.getLogger(BoardDao.class);
public List<Map<String, Object>> boardList(Map<String, Object> pMap) {
logger.info("boardList 호출");
List<Map<String, Object>> bList = null;
if(bList == null) { // NullPointerException 방어코드
bList = new ArrayList<>();
Map<String, Object> rMap = new HashMap<>();
rMap.put("BM_TITLE", "공지사항1");
rMap.put("BM_WRITER", "김춘추");
bList.add(rMap);
rMap = new HashMap<>();
rMap.put("BM_TITLE", "공지사항2");
rMap.put("BM_WRITER", "이성계");
bList.add(rMap);
rMap = new HashMap<>();
rMap.put("BM_TITLE", "공지사항3");
rMap.put("BM_WRITER", "강감찬");
bList.add(rMap);
}
return bList;
}
}
<스프링부트 -boardList.jsp>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.util.List, java.util.Map" %>
<%
List<Map<String, Object>> bList = null;
bList = (List<Map<String, Object>>)request.getAttribute("bList");
//if(bList != null){
for(int i=0; i<bList.size(); i++) {
Map<String, Object> rMap = bList.get(i);
out.print("제목:" + rMap.get("BM_TITLE") + "<br />");
out.print("작성자:" + rMap.get("BM_WRITER") + "<br />" + "<hr />");
}
//}
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>계층형 게시판(WEB-INF)</title>
</head>
<body>
<h3>계층형 게시판</h3>
</body>
</html>
<pojo3 우편번호 - HandlerMapping.java>
package com.pojo.step3;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
public class HandlerMapping {
static Logger logger = Logger.getLogger(HandlerMapping.class);
/***************************************
* @param upmu[](upmu[0]=업무명,폴더명 | upmu[1]=메소드명, 기능명, 페이지이름)
* @param request -> 1-1, 1-2와는 다르게 인터페이스를 implements하지 않는다
* @param response -> HttpServlet
* Q. 어디서 받아오는가?
* @return Object
* 테스트 -> http://localhost:9000/board3/boardList.st3
***************************************/
public static Object getController(String[] upmu, HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
logger.info(upmu[0]+", "+upmu[1]);
Controller3 controller = null;
String path = null;
Object obj = null;
ModelAndView mav = null;
// common
if("common".equals(upmu[0])) {
controller = new CommonController();
// 우편번호 조회
if("zipcodeList".equals(upmu[1])) {
obj = controller.zipcodeList(req, res);
// 리턴타입이 ModelAndView인 경우
if(obj instanceof ModelAndView) {
return (ModelAndView)obj;
}
// 리턴타입이 String인 경우
else if(obj instanceof String) {
return (String)obj;
}
} // end if zipcodeList if문
}
// 게시판 구현
else if("board3".equals(upmu[0])) {
controller = new Board3Controller();
// 게시글 전체 목록 -> html 화면 출력(text/html)
if("boardList".equals(upmu[1])) {
obj = controller.boardList(req, res);
// 리턴타입이 ModelAndView인 경우
if(obj instanceof ModelAndView) {
return (ModelAndView)obj;
}
// 리턴타입이 String인 경우
else if(obj instanceof String) {
return (String)obj;
}
}
// json 게시글 전체 목록 -> json 화면 출력(application/json)
else if("jsonBoardList".equals(upmu[1])) {
obj = controller.jsonBoardList(req, res);
// 리턴타입이 ModelAndView인 경우
if(obj instanceof ModelAndView) {
return (ModelAndView)obj;
}
// 리턴타입이 String인 경우
else if(obj instanceof String) {
return (String)obj;
}
}
// 글 입력 - 새글쓰기와 댓글쓰기
else if("boardInsert".equals(upmu[1])) {
obj = controller.boardInsert(req, res);
// 리턴타입이 String인 경우
if(obj instanceof String) {
return (String)obj;
}
}
// 이미지 업로드 - 리액트 quill editor 이미지 추가
else if("imageUpload".equals(upmu[1])) {
obj = controller.imageUpload(req, res);
logger.info("imageUpload 호출 => " + obj instanceof String);
// 리턴타입이 String인 경우
if(obj instanceof String) {
return (String)obj;
}
}
// 이미지 다운로드 - 리액트 quill editor 이미지 추가
else if("imageDownload".equals(upmu[1])) {
obj = controller.imageDownload(req, res);
logger.info("imageDownload 호출 => " + obj instanceof String);
// 리턴타입이 String인 경우
if(obj instanceof String) {
return (String)obj;
}
}
// 리액트 -
else if("imageGet".equals(upmu[1])) {
obj = controller.imageGet(req, res);
logger.info("imageGet 호출 => " + obj instanceof String);
// 리턴타입이 String인 경우
if(obj instanceof String) {
return (String)obj;
}
}
// 글 수정 - 첨부파일 수정 유무 고려하기
else if("boardUpdate".equals(upmu[1])) {
obj = controller.boardUpdate(req, res);
// 리턴타입이 String인 경우
if(obj instanceof String) {
return (String)obj;
}
}
// 글 삭제 - 첨부파일 삭제 유무 고려하기
else if("boardDelete".equals(upmu[1])) {
obj = controller.boardDelete(req, res);
// 리턴타입이 String인 경우
if(obj instanceof String) {
return (String)obj;
}
}
// 글 상세보기
else if("boardDetail".equals(upmu[1])) {
obj = controller.boardDetail(req, res);
// 리턴타입이 ModelAndView인 경우
if(obj instanceof ModelAndView) {
return (ModelAndView)obj;
}
// 리턴타입이 String인 경우
else if(obj instanceof String) {
return (String)obj;
}
}
} // end of 게시판 구현
// 인증 관리 구현
else if("auth".equals(upmu[0])) {
}
// 회원 관리 구현
else if("member".equals(upmu[0])) {
}
// 주문 관리 구현
else if("order".equals(upmu[0])) {
}
return obj;
}
}
<pojo3 우편번호 - Controller3.java>
package com.pojo.step3;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// javascript기반의 UI API
// 리액트는 바닐라스크립트 + ES6(주요이슈-spread, module, arrow),ES7 + html 섞어쓰기
public interface Controller3 {
public Object zipcodeList(HttpServletRequest req, HttpServletResponse res);
public Object jsonBoardList(HttpServletRequest req, HttpServletResponse res);
public Object boardList(HttpServletRequest req, HttpServletResponse res);
public Object boardDetail(HttpServletRequest req, HttpServletResponse res);
public Object imageUpload(HttpServletRequest req, HttpServletResponse res);
public Object imageDownload(HttpServletRequest req, HttpServletResponse res);
public Object imageGet(HttpServletRequest req, HttpServletResponse res);
public Object boardInsert(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException;
public Object boardUpdate(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException;
public Object boardDelete(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException;
}
<pojo3 우편번호 - CommonController.java>
package com.pojo.step3;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import com.util.HashMapBinder;
public class CommonController implements Controller3 {
Logger logger = Logger.getLogger(CommonController.class);
private CommonLogic commonLogic = new CommonLogic();
@Override
public ModelAndView zipcodeList(HttpServletRequest req, HttpServletResponse res) {
logger.info("zipcodeList 호출");
List<Map<String, Object>> zList = null;
// 사용자가 조건 검색을 원하는 경우 - 조건 값을 전달할 객체 생성함
// MyBatis에서는 동적쿼리를 지원하므로 하나로 2가지 경우 사용 가능함
Map<String, Object> pMap = new HashMap<>();
HashMapBinder hmb = new HashMapBinder(req);
hmb.bind(pMap);
zList = commonLogic.zipcodeList(pMap);
ModelAndView mav = new ModelAndView(req);
mav.setViewName("common/zipcodeList");
mav.addObject("zList", zList);
return mav; // 리턴이 mav면 webapp/WEB-INF/views/common 아래의 jsp
}
@Override
public Object jsonBoardList(HttpServletRequest req, HttpServletResponse res) {
return null;
}
@Override
public Object boardList(HttpServletRequest req, HttpServletResponse res) {
return null;
}
@Override
public Object boardDetail(HttpServletRequest req, HttpServletResponse res) {
return null;
}
@Override
public Object imageUpload(HttpServletRequest req, HttpServletResponse res) {
return null;
}
@Override
public Object imageDownload(HttpServletRequest req, HttpServletResponse res) {
return null;
}
@Override
public Object imageGet(HttpServletRequest req, HttpServletResponse res) {
return null;
}
@Override
public Object boardInsert(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
return null;
}
@Override
public Object boardUpdate(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
return null;
}
@Override
public Object boardDelete(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
return null;
}
}
<pojo3 우편번호 - CommonLogic.java>
package com.pojo.step3;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
// @Service -> 스프링일경우
public class CommonLogic {
Logger logger = Logger.getLogger(CommonLogic.class);
private CommonDao commonDao = new CommonDao();
// @Autowired -> 스프링일경우
public List<Map<String, Object>> zipcodeList(Map<String, Object> pMap) {
logger.info("zipcodeList 호출" + pMap);
List<Map<String, Object>> zList = null;
zList = commonDao.zipcodeList(pMap);
return zList;
}
}
<pojo3 우편번호 - CommonDao.java>
package com.pojo.step3;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.log4j.Logger;
import com.util.MyBatisCommonFactory;
/*
* 스프링일경우
* @Service
* @Repository
*/
public class CommonDao {
Logger logger = Logger.getLogger(CommonDao.class);
MyBatisCommonFactory mcf = new MyBatisCommonFactory();
public List<Map<String, Object>> zipcodeList(Map<String, Object> pMap) {
logger.info("zipcodeList 호출");
List<Map<String, Object>> zList = null;
SqlSessionFactory sqlSessionFactory = null;
SqlSession sqlSession = null;
try {
sqlSessionFactory = mcf.getSqlSessionFactory();
sqlSession = sqlSessionFactory.openSession();
zList = sqlSession.selectList("zipcodeList", pMap);
logger.info(zList);
} catch (Exception e) {
e.printStackTrace();
}
return zList;
}
}
<pojo3 우편번호 - common.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="com.mybatis.mapper.CommonMapper">
<!-- 우편번호 검색 -->
<select id="zipcodeList" parameterType="map" resultType="map">
SELECT zipcode, address FROM zipcode_t
WHERE dong LIKE '%'||#{dong}||'%'
</select>
</mapper>
<pojo3 우편번호 - MyBatisConfig.xml>
<?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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.OracleDriver" />
<property name="url"
value="jdbc:oracle:thin:@localhost:1521:orcl11" />
<property name="username" value="scott" />
<property name="password" value="tiger" />
</dataSource>
</environment>
</environments>
<mappers>
<!-- 업무에따라 관리할 쿼리문을 담을 xml문서의 물리적인 위치와 파일명을 등록할것 -->
<mapper resource="com/mybatis/mapper/test.xml" />
<mapper resource="com/mybatis/mapper/member.xml" />
<mapper resource="com/mybatis/mapper/board.xml" />
<mapper resource="com/mybatis/mapper/common.xml" />
<mapper resource="com/util/book.xml" />
<mapper resource="com/util/member2.xml" />
</mappers>
</configuration>
<pojo3 우편번호 - zipcodeList.jsp>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@page import="java.util.*"%>
<%
List<Map<String,Object>> zList =
(List<Map<String,Object>>)request.getAttribute("zList");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>우편번호 검색기</title>
</head>
<body>
<h3>우편번호 검색기</h3>
<%
if(zList != null) {
for(int i=0; i<zList.size(); i++){
out.print(zList.get(i) + "<br />");
}
}
%>
</body>
</html>
<pojo3 우편번호 - memberMgr.jsp>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원관리 시스템</title>
<%@ include file="../common/easyUI_common.jsp" %>
</head>
<body>
<script>
$(document).ready(function(){
$("#btn_search").linkbutton({
onClick:function(){
const u_dong = $("#_easyui_textbox_input1").val();
if(u_dong == null || u_dong.length < 1) {
alert("검색할 동을 입력하세요");
// 동 정보가 없으면 처음부터 새로 시작해야하니 return함
return;
} else {
console.log('사용자가 입력한 동이름 => ' + u_dong);
// 오라클 서버를 경유해서 조회된 결과를 datagrid에 출력해보기
}
location.href = "./zipcodeList.st3?dong="+u_dong;
}
}) // end of 찾기버튼
$('#dong').textbox('textbox').bind('keydown', function(e){
const u_dong = $("#_easyui_textbox_input1").val();
if(e.keyCode == 13){
alert('사용자가 입력한 동이름은 ' + u_dong);
}
})
})
</script>
<!--======================= 우편번호 검색기 =======================-->
<div id="dlg_zipcode" style="width:100%;max-width:600px;padding:30px 30px;">
<input class="easyui-textbox" id="dong" name="dong" labelPosition="top" data-options="prompt:'동이름 이나 주소정보 입력...'" style="width:210px;">
<a id="btn_search" href="#" class="easyui-linkbutton" data-options="iconCls:'icon-search'">찾기</a>
<div style="margin-bottom:10px;"></div>
<table id="dg_zipcode">
</table>
</div>
<!--======================= 우편번호 검색기 =======================-->
</body>
</html>
'국비학원 > 수업기록' 카테고리의 다른 글
국비 지원 개발자 과정_Day75 (1) | 2023.03.16 |
---|---|
국비 지원 개발자 과정_Day74 (1) | 2023.03.15 |
국비 지원 개발자 과정_Day72 (1) | 2023.03.13 |
국비 지원 개발자 과정_Day71 (1) | 2023.03.10 |
국비 지원 개발자 과정_Day70 (1) | 2023.03.09 |
댓글