DB생성
create table sbbs
(boardNum number(9) not null,
name varchar2(20) not null,
pwd varchar2(10),
email varchar2(50),
subject varchar2(50) not null,
content varchar2(4000) not null,
ipAddr varchar2(20) not null,
hitCount number(9) not null,
created date,
constraint pk_bbs_boardNum primary key(boardNum));
2. jsp 파일 수정
1.created.jsp
자바스크립트 부분 action 수정
/* 글쓰기 완료시 mode값을 insert 로 넘겨준다. */
if (f.mode.value=="insert")
f.action="<%=cp%>/bbs/created.action";
else
f.action="<%=cp%>/bbs/updated.action";
f.submit();
3. created.jsp
보내는 부분
<div id="bbsCreated_footer">
<c:if test="${mode=='update'}">
<input type="hidden" name="boardNum" value="${dto.boardNum}">
</c:if>
<input tpye="hidden" name="mode" value="${mode}">
<input type="hidden" name="pageNum" value="${pageNum}">
<input type="hidden" name="searchKey" value="${searchKey}">
<input type="hidden" name="searchValue" value="${searchValue}">
<input type="button" value="등록하기" class="btn2" onclick="sendIt();"/>
<input type="reset" value="다시입력" class="btn2" onclick="document.myForm.subject.focus();"/>
<input type="button" value="작성취소" class="btn2" onclick="javascript:location.href='<%=cp%>/bbs/list.action';"/>
4. list.jsp
스크립트 추가
<script type="text/javascript">
function searchData() {
var f = document.searchForm;
f.action = "<%=cp%>/bbs/list.action;
f.submit();
}
</script>
5. Command 생성
DTO 역할
package com.bbs;
//스프링의 DTO
public class BoardCommand {
private int listNum;//일련번호
private int boardNum;//여기부터 hitCount까지는 테이블에있는것
private String subject;
private String name;
private String email;
private String pwd;
private String content;
private String ipAddr;
private String created;
private int hitCount;
private String mode;
private String pageNum;
public int getListNum() {
return listNum;
}
public void setListNum(int listNum) {
this.listNum = listNum;
}
public int getBoardNum() {
return boardNum;
}
public void setBoardNum(int boardNum) {
this.boardNum = boardNum;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getIpAddr() {
return ipAddr;
}
public void setIpAddr(String ipAddr) {
this.ipAddr = ipAddr;
}
public String getCreated() {
return created;
}
public void setCreated(String created) {
this.created = created;
}
public int getHitCount() {
return hitCount;
}
public void setHitCount(int hitCount) {
this.hitCount = hitCount;
}
public String getMode() {
return mode;
}
public void setMode(String mode) {
this.mode = mode;
}
public String getPageNum() {
return pageNum;
}
public void setPageNum(String pageNum) {
this.pageNum = pageNum;
}
}
6. 컨트롤러 작성
1. 객체 생성
// 컨트롤러(분배기) : 어디로 갈지 경로 분배
// 컨트롤러에서 GET,POST방식 메소드 한번에 처리 -> 경량 컨테이너
@Controller("bbs.boardController") // web.xml 이후로 제일먼저 들어오는곳이 controller
public class BoardController {
@Resource(name=="dao")
private CommandDAO dao;
@Resource(name=="myUtil")
private MyUtil myUtil;
}
2. 입력 메소드 작성
리다이렉트 : redirect/주소
@RequestMapping(value="/bbs/created.action",method=(RequestMethod.GET,RequestsetMethod.POST})
public String created(BoardCommand command,HttpRequest request) throws Exception {
// created창에서 넘어오는 mode를 결정해야함
if(command==null) || command.getMode()==null || command.getMode().equals("")) {
//넘어갈 때 mode를 가져가야 한다.
request.setAttribute("mode","insert");
return "board/created";
}
// 입력을 시키는 코딩을 써준다.
int boardNumMax = dao.getIntValue("bbs.boardNumMax");
command.setBoardNum(dao.getIntValue(boardNumMax + 1);
command.setIpAddr(request.getRemoteAddr());
dao.insertData("bbs.insertData",command);
// 스프링에서는 리다이렉트
return "redirect:/bbs/list.action"; // DB작업 후 리다이렉트 가상주소 써놓는다
}
전체 페이지 소스코드
MyUtil.java
페이징처리
package com.util;
import org.springframework.stereotype.Service;
// Serice : 일반클래스 메소드에 의존성주입을해서 가져다가 쓸수있게 됨
@Service("myUtil")
public class MyUtil {
//전체페이지 구함
public int getPageCount(int numPerPage,int dataCount) { // 페이지 하나당 5개의 게시물 총 12개
int pageCount = 0;
// 총 페이지 개수
pageCount = dataCount / numPerPage;
if(dataCount % numPerPage != 0) { // (12 % 5 != 0) 1장더 추가
pageCount++;
}
return pageCount; // 전체 페이지 개수
}
// 페이징처리 메소드
public String pageIndexList(int currentPage, int totalPage, String listUrl) {
int numPerBlock = 5; // 한페이지에 표시할 게시물 수
int currentPageSetup; // ◀ 내가 이전을 누르게되면 5페이지가 나옴 (왼쪽 화살표 값)
int page; // 출력할 i
StringBuffer sb = new StringBuffer();
// 현재페이지또는 전체페이지 0이면 null 반환
if(currentPage == 0 || totalPage == 0) {
return "null";
}
// 검색이 여부
if(listUrl.indexOf("?") != -1) {
// ?가 있으면
listUrl = listUrl + "&"; // list.jsp? searchKey=subject & searchValue=aa & pageNum=2
} else {
// 물음표가 없으면 물음표를 붙임
listUrl = listUrl + "?";
}
// ◀이전 값을 구하는 공식
// ◀이전값 5 = 6 5 5
// 10 = 11 5 5
currentPageSetup = (currentPage/numPerBlock)*numPerBlock;
// 조건에 만족하면 ◀이전 만듬
// 10 5
if(currentPage % numPerBlock == 0) { // 10으로 나눴을때 0이므로
// 5 10 5
currentPageSetup = currentPageSetup - numPerBlock; // 10이여도 5가 나옴
}
// 15 5 6
if(totalPage > numPerBlock && currentPageSetup > 0) {
//<a href="list.jsp?pageNum=2>◀이전</a>"를 만드는 코딩 pageNum은 현재 페이지
sb.append("<a href=\"" + listUrl + "pageNum="
+ currentPageSetup + "\">◀이전</a> ");
}
// ◀ 6 7 8 9 10
// 6 5
page = currentPageSetup + 1; // 시작값 ◀이전 부터 6,7,8,9,10
// 6 12 6 5(◀이전값) 5
// .
// .
// 10 12 10 5 5
while(page <= totalPage && page <= (currentPageSetup + numPerBlock)) { // page 증가시 허용되는 수만큼 찍힘
// 현재페이지가 보고있는 페이지면 색깔표시
if(page == currentPage) {
sb.append("<font color=\"Fuchsia\">" + page + "</font> ");
//<font color="Fuchsia">9</font>
} else {
//보고있는 페이지가 아니면
sb.append("<a href=\"" + listUrl + "pageNum=" + page +
"\">" + page + "</a> ");
}
// 만족하면 6부터 10까지 찍힘
page++;
}
// 다음▶
// ◀이전 6 7 8 9 10 다음▶
// ◀이전 11 12
// ▶다음 값을 구하는 공식
// 12 1 5 다음▶생김
// 12 10 5 다음▶안생김
if(totalPage - currentPageSetup > numPerBlock) {
//<a href="list.jsp?pageNum=11">다음▶</a>
sb.append("<a href=\"" + listUrl + "pageNum=" +
page + "\">다음▶</a> ");
}
return sb.toString();
}
// 자바스크립트로 페이징 처리 하기
// listUrl이 필요없다.
public String pageIndexList(int currentPage, int totalPage ) {
int numPerBlock = 5;
int currentPageSetup;
int page;
String strList = "";
if(currentPage==0) {
return "";
}
// ◀이전 값을 구하는 공식
currentPageSetup = (currentPage/numPerBlock) * numPerBlock;
if(currentPage % numPerBlock == 0) {
currentPageSetup = currentPageSetup - numPerBlock; // 5 = 10 - 5
}
// 조건에 만족하면 ◀이전 만듬
if(totalPage > numPerBlock && currentPageSetup>0) {
strList = "<a onclick='listPage(" + currentPageSetup + ");'>◀이전</a> ";
}
// ◀ 6 7 8 9 10 구하는 공식
page = currentPageSetup + 1;
while((page<=totalPage) && (page<=currentPageSetup + numPerBlock)) {
if(page==currentPage) {
strList += "<font color='Fuchsia'>" + page + "</font> ";
} else {
// 모든 페이지작업을 list한테 넘긴다.
strList += "<a onclick='listPage(" + page +");'>" +
page +"</a> ";
}
page++;
}
// 다음 ▶값 구하는 공식
if(totalPage - currentPageSetup > numPerBlock) {
strList = "<a onclick='listPage(" + page + ");'>다음▶</a> ";
}
return strList;
}
}
파일 업로드 , 다운로드 해주는 메소드를 가진 클래스
FileManager.java
package com.util;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Calendar;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;
// @service : 일반클래스를 객체화 시킨다.
@Service("fileManager")
public class FileManager {
// 파일이 이름이 들어옴
// ★03-22 추가 InputStream 이 파일을 관리함
// (어떤파일을 업로드할지 , 경로)
public static String doFileUpload(InputStream is,String originalFileName , String path) throws IOException {
// upload에 a.txt가 오면
// a.txt 에서 txt를 빼내고
// 파일명과 상관없이 20220310115020xxxxx 에 .txt를 붙일것이다
// 새롭게 저장되는 saveFileName이다
// 반환값으로 받아내야만 오리지널 파일네임과 세이브 파일네임을 db에 저장하게된다.
// 그래서 반환값이 String이다.
String newFileName = null;
if(originalFileName.equals("")) {
return null;
}
// 파일 확장자
String fileExt = originalFileName.substring(originalFileName.lastIndexOf(".")); // .txt -> txt
if(fileExt==null || fileExt.equals("")) {
return null;
}
// newFileName : 서버에 저장할 새로운 파일 이름 생성(업로드할곳임)
// 1$ : Calendar.getInstance()로 값을 한번에 처리한다.
newFileName = String.format("%1$tY%1$tm%1$td%1$tH%1$tM%1$tS",Calendar.getInstance());
newFileName += System.nanoTime(); // nanoTime(): 중복되지 않게 한다.
newFileName += fileExt; // 파일 확장자를 붙인다.
File f = new File(path);
// 파일이 존재하지 않으면 생성
if(!f.exists()) {
f.mkdirs();
}
// 저장할파일경로 = 경로 + / + 새로운파일이름
String fullFilePath = path + File.separator + newFileName;
// ★3-22
// 스프링은 FileCopyUtils 한줄로 파일업로드를 해준다.
FileCopyUtils.copy(is, new FileOutputStream(fullFilePath));
return newFileName;
}
// 파일다운로드
// 다운로드는 서버에서 클라이언트로 response담아서 준다.
// 다운로드는 response가 필수이다.
// response , 파일 저장이름 , 오리지널파일이름 , 경로 매개변수로 받는다.
public static boolean doFileDownload(HttpServletResponse response,String saveFileName, String originalFileName,String path) {
// 오리지널파일 이름이 필요한 이유 ->
// a.txt를 올렸는데 a.txt로 저장되는데 b라는사람이 a.txt 올리게되면 a1.txt로저장
// a1이라는 이름으로 다운받을때 a1를 a.txt로 바꿔준다(오리지널파일네임).
try {
// 파일경로 = 경로 + / + 저장할파일명
String filePath = path + File.separator + saveFileName;
// 오리지널파일이 없는경우 saveFile이름으로 넣는다.
if(originalFileName==null || originalFileName.equals("")) {
originalFileName = saveFileName; // cat.jpg (순수한)
}
// 파일을 다운받아 클라이언트 컴에 저장할때
// 파일 한글 이름 깨짐 방지 ( 반드시 써야한다. 한글파일을 받음 )
// 한글2바이트 영문 1바이트 웹에서는 한글을 3바이트로 쓰려고 UTF-8로씀
// ISO 생략가능 8859_1 만 써도 된다.
originalFileName = new String(originalFileName.getBytes("euc-kr"),"ISO-8859-1");
// 파일경로 존재시 파일다운 (없을시 자바스크립트 에러 출력)
File f = new File(filePath);
// 존재하지않으면
if(!f.exists()) {
return false;
}
// html 를 utf-8로 처리한다고 알려줬었음
// application : 모든 프로그램에서 돌아감
// abc.txt 앞에있는건 특수기호 아니면 모두다 가능 뒤에는 3자리
// .를 octet라고 부름 , 모든파일은 application서 만들고 octet라고 구분지음
response.setContentType("application/octet-stream"); // 파일형식지정
// 내려보냄
// 서버가 파일을 read 읽어서 내보낼때 out를 쓴다.
// setHeader(String name, String value) : name 헤더의 값을 value로 지정한다.
// 데이터형식/성향설정 (attachment: 첨부파일)
response.setHeader("Content-disposition","attachment;fileName=" + originalFileName);
// 버퍼로 객체를 생성할 때 데이터를 읽어올 파일을 지정
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f));
// 버퍼의 출력스트림을 출력
OutputStream out = response.getOutputStream();
int data;
byte[] bytes = new byte[4096];// 자동으로 내보내줌
// 4096 바이트로 읽어와서 없을때까지 읽어옴
// bytes의 0번째부터 4096번째 까지 읽어와서
while((data=bis.read(bytes, 0, 4096))!=-1) {
out.write(bytes,0,data); // 0부터 data의 양만큼 쓴다.
}
out.flush();
out.close();
bis.close();
} catch (Exception e) {
System.out.println(e.toString());
// 에러가 났으면 false
return false;
}
return true;
}
// 파일을 삭제하는 메소드
public static void doFileDelete(String fileName,String path) {
// 파일삭제할때 파일이름,파일경로 필요
try {
// path는 서블릿의 파일저장경로 path를 넘겨줄건데
// 파일의 이름은 db에 있다
// 그리고 업로드된 파일 삭제하고 db정보도 삭제해야한다.
// 파일 경로
String filePath = path + File.separator + fileName;
File f = new File(filePath); // 경로를 넘겨줌
// 파일이 있으면 지워라 - 물리적인 파일삭제
if(f.exists()) {
f.delete(); // 파일삭제후 db도 삭제 작업 해줘야함
}
} catch (Exception e) {
System.out.println(e.toString());
}
}
}
아이바티스 DB연결 객체 생성
CommonDAO 인터페이스
데이터 추가
수정
삭제하는경우의수
레코드가져오기
package com.util.dao;
import java.util.List;
import java.util.Map;
public interface CommonDAO {
//데이터 추가
public void insertData(String id, Object value); // 이름마음대로지만 inser는 반드시 만들어줘야함
//데이터 수정
public int updateData(String id,Object value);
public int updateData(String id,Map<String, Object> map);
//데이터 삭제하는 경우의 수 3개
public int deleteData(String id,Object value); // 이것만씀
public int deleteData(String id,Map<String, Object> map); // 이것만씀
public int deleteAllData(String id);
//레코드 가져오기
public Object getReadData(String id); // 하나의 데이터가져오기(자주쓴다)
public Object getReadData(String id,Object value);
public Object getReadData(String id,Map<String, Object> map);
//하나의 데이터를 가져오는 경우의 수
public int getIntValue(String id); // 하나의 데이터가져오기(자주쓴다)
public int getIntValue(String id,Object value);
public int getIntValue(String id,Map<String, Object> map);
//많은데이터를 가져오기
public List<Object> getListData(String id); // 하나의 데이터가져오기(자주쓴다)
public List<Object> getListData(String id,Object value);
public List<Object> getListData(String id,Map<String, Object> map);
}
CommonDAO.java 인터페이스를 구현한
CommonDAOImpl 클래스
package com.util.dao;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.ibatis.SqlMapClientTemplate;
import org.springframework.stereotype.Repository;
@Repository("dao")
public class CommonDAOImpl implements CommonDAO{
@Autowired
private SqlMapClientTemplate sqlMapClientTemplate;
public void setSqlMapClientTemplate(SqlMapClientTemplate sqlMapClientTemplate) {
this.sqlMapClientTemplate = sqlMapClientTemplate;
}
@Override
public void insertData(String id, Object value) {
try {
sqlMapClientTemplate.insert(id, value);
} catch (Exception e) {
System.out.println(e.toString());
}
}
@Override
public int updateData(String id, Object value) {
int result = 0;
try {
result = sqlMapClientTemplate.update(id, value);
} catch (Exception e) {
System.out.println(e.toString());
}
return result;
}
@Override
public int updateData(String id, Map<String, Object> map) {
int result = 0;
try {
result = sqlMapClientTemplate.update(id, map);
} catch (Exception e) {
System.out.println(e.toString());
}
return result;
}
@Override
public int deleteData(String id, Object value) {
int result = 0;
try {
result = sqlMapClientTemplate.delete(id, value);
} catch (Exception e) {
System.out.println(e.toString());
}
return result;
}
@Override
public int deleteData(String id, Map<String, Object> map) {
int result = 0;
try {
result = sqlMapClientTemplate.delete(id, map);
} catch (Exception e) {
System.out.println(e.toString());
}
return result;
}
@Override
public int deleteAllData(String id) {
int result = 0;
try {
result = sqlMapClientTemplate.delete(id);
} catch (Exception e) {
System.out.println(e.toString());
}
return result;
}
@Override
public Object getReadData(String id) {
try {
return sqlMapClientTemplate.queryForObject(id);
} catch (Exception e) {
System.out.println(e.toString());
}
return null;
}
@Override
public Object getReadData(String id, Object value) {
try {
return sqlMapClientTemplate.queryForObject(id, value);
} catch (Exception e) {
System.out.println(e.toString());
}
return null;
}
@Override
public Object getReadData(String id, Map<String, Object> map) {
try {
return sqlMapClientTemplate.queryForObject(id, map);
} catch (Exception e) {
System.out.println(e.toString());
}
return null;
}
@Override
public int getIntValue(String id) {
try {
return ((Integer)sqlMapClientTemplate.queryForObject(id)).intValue();
} catch (Exception e) {
System.out.println(e.toString());
}
return 0;
}
@Override
public int getIntValue(String id, Object value) {
try {
return ((Integer)sqlMapClientTemplate.queryForObject(id, value)).intValue();
} catch (Exception e) {
System.out.println(e.toString());
}
return 0;
}
@Override
public int getIntValue(String id, Map<String, Object> map) {
try {
return ((Integer)sqlMapClientTemplate.queryForObject(id, map)).intValue();
} catch (Exception e) {
System.out.println(e.toString());
}
return 0;
}
@SuppressWarnings("unchecked")
@Override
public List<Object> getListData(String id) {
try {
return (List<Object>)sqlMapClientTemplate.queryForList(id);
} catch (Exception e) {
System.out.println(e.toString());
}
return null;
}
@SuppressWarnings("unchecked")
@Override
public List<Object> getListData(String id, Object value) {
try {
return (List<Object>)sqlMapClientTemplate.queryForList(id, value);
} catch (Exception e) {
System.out.println(e.toString());
}
return null;
}
@SuppressWarnings("unchecked")
@Override
public List<Object> getListData(String id, Map<String, Object> map) {
try {
return (List<Object>)sqlMapClientTemplate.queryForList(id, map);
} catch (Exception e) {
System.out.println(e.toString());
}
return null;
}
}
bbs_sqlMap.xml
아이바티스 를 이용하여 쿼리문 사용
쿼리문 관리
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org//dtd/sql-map-2.dtd">
<sqlMap namespace="bbs">
<!-- 게시물번호 -->
<select id="boardNumMax" resultClass="int">
select nvl(max(boardNum),0) from sbbs
</select>
<!-- 글쓰기 -->
<insert id="insertData" parameterClass="com.bbs.BoardCommand">
insert into sbbs (boardNum,name,pwd,email,subject,content,
ipAddr,hitCount,created) values (#boardNum#,#name#,#pwd#,#email#,#subject#,#content#,
#ipAddr#,0,sysdate)
</insert>
<!-- 검색한 데이터의 개수 -->
<select id="dataCount" resultClass="int" parameterClass="map">
select nvl(count(*),0) from sbbs
where $searchKey$ like '%' || #searchValue# || '%'
</select>
<!-- 검색한 데이터의 리스트 -->
<select id="listData" resultClass="com.bbs.BoardCommand" parameterClass="map">
select * from (
select rownum rnum, data.* from (
select boardNum,name,subject,hitCount,
to_char(created, 'YYYY-MM-DD') created from sbbs
where $searchKey$ like '%' || #searchValue# || '%'
order by boardNum desc) data)
<![CDATA[
where rnum>=#start# and rnum<=#end#
]]>
</select>
<!-- 하나의 데이터 가져옴 -->
<select id="readData" resultClass="com.bbs.BoardCommand" parameterClass="int">
select boardNum,name,pwd,email,subject,content,ipAddr,
hitCount,created from sbbs where boardNum=#boardNum#
</select>
<!-- where ($searchKey$ like '%' || #serachValue# || '%') #searchValue#는 값이 있을 수도 있으므로 #으로 $searchKey$는 subject,name,content 값이 정해져있음 ||는 sql에서 문장이어줌 -->
<!-- #boeardNum# 이 5 이면 boardNum은 6 boardNum 오름차순 -->
<select id="preReadData" resultClass="com.bbs.BoardCommand" parameterClass="map">
select rownum,data.* from (
select boardNum,subject from sbbs
where ($searchKey$ like '%' || #searchValue# || '%')
and (boardNum>#boardNum#) order by boardNum asc) data
where rownum=1
)
</select>
<!-- #boeardNum# 이 5 이면 boardNum은 4 boardNum 내림차순-->
<select id="nextReadData" resultClass="com.bbs.BoardCommand" parameterClass="map">
select rownum,data.* from (
select boardNum,subject from sbbs
where ($searchKey$ like '%' || #searchValue# || '%')
<![CDATA[
and (boardNum<#boardNum#) order by boardNum desc) data
where rownum=1
]]>
</select>
<!-- 조회수 증가 -->
<update id="updateHitCount" parameterClass="int">
update sbbs set hitCount=hitCount+1 where boardNum=#boardNum#
</update>
<!-- 게시물 수정 -->
<update id="updateData" parameterClass="com.bbs.BoardCommand">
update sbbs set name=#name#,pwd=#pwd#,email=#email#,
subject=#subject#,content=#content# where boardNum=#boardNum#
</update>
<!-- 게시물 삭제 -->
<delete id="deleteData" parameterClass="int">
delete sbbs where boardNum=#boardNum#
</delete>
</sqlMap>
게시판 리스트를 보여주는 jsp 페이지
list.jsp
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
request.setCharacterEncoding("UTF-8");
String cp = request.getContextPath();
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>게 시 판</title>
<link rel="stylesheet" type="text/css" href="<%=cp%>/board/css/style.css"/>
<link rel="stylesheet" type="text/css" href="<%=cp%>/board/css/list.css"/>
<script type="text/javascript">
function searchData() {
var f = document.searchForm;
f.action = "<%=cp%>/bbs/list.action";
f.submit();
}
</script>
</head>
<body>
<!-- 게시판 리스트 -->
<div id="bbsList">
<div id="bbsList_title">
게 시 판 스프링2.5
</div>
<div id="bbsList_header">
<div id="leftHeader">
<form action="" method="post" name="searchForm">
<select name="searchKey" class="selectField">
<option value="subject">제목</option>
<option value="name">작성자</option>
<option value="content">내용</option>
</select>
<input type="text" name="searchValue" class="textField"/>
<!-- 검색 시 -->
<input type="button" value=" 검 색 " class="btn2" onclick="searchData();"/>
</form>
</div>
<div id="rightHeader">
<!-- 글올리기 -->
<input type="button" value=" 글올리기 " class="btn2"
onclick="javascript:location.href='<%=cp%>/bbs/created.action';"/>
</div>
</div>
<div id="bbsList_list">
<div id="title">
<dl>
<dt class="num">번호</dt>
<dt class="subject">제목</dt>
<dt class="name">작성자</dt>
<dt class="created">작성일</dt>
<dt class="hitCount">조회수</dt>
</dl>
</div>
<div id="lists">
<!-- DB에 있는 모든 게시물 리스트 출력 -->
<c:forEach var="dto" items="${lists }">
<dl>
<dd class="num">${dto.listNum }</dd>
<dd class="subject"><a href="${urlArticle }&boardNum=${dto.boardNum }">${dto.subject }</a></dd>
<dd class="name">${dto.name }</dd>
<dd class="created">${dto.created }</dd>
<dd class="hitCount">${dto.hitCount }</dd>
</dl>
</c:forEach>
</div>
<div id="footer">
<p>
<!-- 게시물 수 여부에 따라 출력 -->
<c:if test="${totalDataCount!=0 }">
${pageIndexList }
</c:if>
<c:if test="${totalDataCount==0 }">
등록된 게시물이 없습니다.
</c:if>
</div>
</div>
</div>
</body>
</html>
게시판 리스트 -> 게시물을 등록하는 jsp 페이지
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
request.setCharacterEncoding("UTF-8");
String cp = request.getContextPath();
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>게 시 판(Spring2.5)</title>
<link rel="stylesheet" type="text/css" href="<%=cp%>/board/css/style.css"/>
<link rel="stylesheet" type="text/css" href="<%=cp%>/board/css/created.css"/>
<script type="text/javascript" src="<%=cp%>/board/js/util.js"></script>
<script type="text/javascript">
function sendIt(){
var f = document.myForm;
str = f.subject.value;
str = str.trim();
if(!str){
alert("\n제목을 입력하세요.");
f.subject.focus();
return;
}
f.subject.value = str;
str = f.name.value;
str = str.trim();
if(!str){
alert("\n이름을 입력하세요.");
f.name.focus();
return;
}
/* if(!isValidKorean(str)){
alert("\n이름을 정확히 입력하세요.");
f.name.focus()
return;
} */
f.name.value = str;
if(f.email.value){
if(!isValidEmail(f.email.value)){
alert("\n정상적인 E-Mail을 입력하세요.");
f.email.focus();
return;
}
}
str = f.content.value;
str = str.trim();
if(!str){
alert("\n내용을 입력하세요.");
f.content.focus();
return;
}
f.content.value = str;
str = f.pwd.value;
str = str.trim();
if(!str){
alert("\n패스워드를 입력하세요.");
f.pwd.focus();
return;
}
f.pwd.value = str;
/* 글쓰기 완료시 mode값을 insert 로 넘겨준다. */
if (f.mode.value=="insert") {
f.action = "<%=cp%>/bbs/created.action";
}else{
f.action = "<%=cp%>/bbs/updated.action";
}
f.submit();
}
</script>
</head>
<body>
<div id="bbs">
<div id="bbs_title">
게 시 판(Spring2.5)
</div>
<!-- 글쓰기 -->
<form action="" method="post" name="myForm">
<div id="bbsCreated">
<div class="bbsCreated_bottomLine">
<dl>
<dt>제 목</dt>
<dd>
<input type="text" name="subject" value="${dto.subject }" size="60"
maxlength="100" class="boxTF"/>
</dd>
</dl>
</div>
<div class="bbsCreated_bottomLine">
<dl>
<dt>작성자</dt>
<dd>
<input type="text" name="name" value="${dto.name }" size="35"
maxlength="20" class="boxTF"/>
</dd>
</dl>
</div>
<div class="bbsCreated_bottomLine">
<dl>
<dt>E-Mail</dt>
<dd>
<input type="text" name="email" value="${dto.email }" size="35"
maxlength="50" class="boxTF"/>
</dd>
</dl>
</div>
<div id="bbsCreated_content">
<dl>
<dt>내 용</dt>
<dd>
<textarea rows="12" cols="63" name="content"
class="boxTA">${dto.content }</textarea>
</dd>
</dl>
</div>
<div class="bbsCreated_noLine">
<dl>
<dt>패스워드</dt>
<dd>
<input type="password" name="pwd" value="${dto.pwd }" size="35"
maxlength="7" class="boxTF"/>
(게시물 수정 및 삭제시 필요!!)
</dd>
</dl>
</div>
</div>
<!-- 보내는 부분 -->
<div id="bbsCreated_footer">
<!-- pageNum , mode 입력되지않고 값을 hidden으로 넘긴다. -->
<input type="hidden" name="pageNum" value="${pageNum }"/>
<input type="hidden" name="mode" value="${mode }"/>
<!-- mode가 insert 입력창 -->
<c:if test="${mode=='insert' }">
<input type="button" value=" 등록하기 " class="btn2" onclick="sendIt();"/>
<input type="reset" value=" 다시입력 " class="btn2"
onclick="document.myForm.subject.focus();"/>
<input type="button" value=" 작성취소 " class="btn2"
onclick="javascript:location.href='<%=cp%>/bbs/list.action';"/>
</c:if>
<!-- 수정창이면 boardNum 입력되지않고 값을 hidden으로 넘긴다. -->
<c:if test="${mode=='update' }">
<input type="hidden" name="boardNum" value="${dto.boardNum }"/>
<input type="button" value=" 수정하기 " class="btn2" onclick="sendIt();"/>
<input type="button" value=" 수정취소 " class="btn2"
onclick="javascript:location.href='<%=cp%>/bbs/list.action?pageNum=${pageNum }';"/>
</c:if>
</div>
</form>
</div>
</body>
</html>
게시판 리스트 -> 게시물 클릭시 보여지는 jsp 페이지
article.jsp
request.setAttribute 로 넘어온 dto 데이터 출력
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
request.setCharacterEncoding("UTF-8");
String cp = request.getContextPath();
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>게 시 판</title>
<link rel="stylesheet" type="text/css" href="<%=cp%>/board/css/style.css"/>
<link rel="stylesheet" type="text/css" href="<%=cp%>/board/css/article.css"/>
<script type="text/javascript">
// 수정버튼
function updateData() {
// 주소 생성
var boardNum = "${dto.boardNum}";
var param = "${params}"; // params에 기본적으로 pageNum,searchkey,searchValue
var params = "?boardNum=" + boardNum + "&" + param;
var url = "<%=cp%>/bbs/updated.action" + params;
location.replace(url);
}
// 삭제버튼
function deleteData() {
var boardNum = "${dto.boardNum}";
var param = "${params}";
var params = "?boardNum=" + boardNum + "&" + param;
var url = "<%=cp%>/bbs/deleted.action" + params;
location.replace(url);
}
</script>
</head>
<body>
<!-- request.setAttribute 로 넘어온 dto 데이터 출력 -->
<div id="bbs">
<div id="bbs_title">
게 시 판 (Spring2.5)
</div>
<div id="bbsArticle">
<div id="bbsArticle_header">
${dto.subject }
</div>
<div class="bbsArticle_bottomLine">
<dl>
<dt>작성자</dt>
<dd>
${dto.name }
<c:if test="${!empty dto.email }"> <!-- !empty 값이 있으면 -->
(<a href="mailto:${dto.email }">${dto.email })</a> <!-- 메일클릭하면 메일가는 창 -->
</c:if>
</dd>
<dt>줄수</dt>
<dd>${lineSu }</dd>
</dl>
</div>
<div class="bbsArticle_bottomLine">
<dl>
<dt>등록일</dt>
<dd>${dto.created }</dd>
<dt>조회수</dt>
<dd>${dto.hitCount }</dd>
</dl>
</div>
<div id="bbsArticle_content">
<table width="600" border="0">
<tr>
<td style="padding-left: 20px 80px 20px 62px;"
valign="top" height="200">
${dto.content }
</td>
</tr>
</table>
</div>
<!-- preSubject는 이전글 -->
<div class="bbsArticle_bottomLine">
이전글:
<c:if test="${!empty preSubject}">
<a href="<%=cp %>/bbs/article.action?${params}&boardNum=${preBoardNum}"> <!-- params : Key,Value preBoardNum : 이전 게시물 번호 -->
${preSubject } <!-- 이전 게시물 제목 -->
</a>
</c:if>
</div>
<!-- nextSubject는 다음글 -->
<div class="bbsArticle_noLine">
다음글:
<c:if test="${!empty nextSubject}">
<a href="<%=cp %>/bbs/article.action?${params}&boardNum=${nextBoardNum}"> <!-- params : Key,Value nextBoardNum : 다음 게시물 번호 -->
${nextSubject } <!-- 다음 게시물 제목 -->
</a>
</c:if>
</div>
</div>
<div class="bbsArticle_noLine" style="text-align: right">
From : ${dto.ipAddr }
</div>
<div id="bbsArticle_footer">
<div id="leftFooter">
<!-- 함수를 호출해서 경로 -->
<input type="button" value=" 수정 " class="btn2" onclick="updateData();"/>
<input type="button" value=" 삭제 " class="btn2" onclick="deleteData();"/>
</div>
<div id="rightFooter">
<!-- 들어왔던 페이지로 다시 돌아간다. params -->
<input type="button" value=" 리스트 " class="btn2"
onclick="javascript:location.href='<%=cp%>/bbs/list.action?${params}';"/>
</div>
</div>
</div>
</body>
</html>
컨트롤러 자바 페이지
분배기 같은 역할 ( 어디로 갈지 경로를 분배한다. )
어노테이션을 사용하였다
컨트롤러에서 GET,POST방식
package com.bbs;
//컨트롤러 : 분배기(어디로 갈지 경로 분배)
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.jasper.tagplugins.jstl.core.Url;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.util.MyUtil;
import com.util.dao.CommonDAO;
// 컨트롤러에서 GET,POST방식 메소드 한번에 처리 -> 경량 컨테이너
@Controller("bbs.boardController")
public class BoardController { // web.xml이후로 제일먼저 들어오는곳 Controller
@Resource(name="dao") //CommonDAOImpl을 사용하는것. //객체생성한걸 가져오는게 @Resource
private CommonDAO dao;
@Resource(name="myUtil")
private MyUtil myUtil; //new = MyUtil();한것과 똑같은 구조
// 글쓰기
@RequestMapping(value="/bbs/created.action",
method= {RequestMethod.GET,RequestMethod.POST})
public String created(BoardCommand command,
HttpServletRequest request) throws Exception{
//created창에서 넘어오는 mode를 결정해야함
if (command==null||command.getMode()==null
|| command.getMode().equals("")) {
//넘어갈 때 mode를 가져가야 한다.
request.setAttribute("mode", "insert");
return "board/created";
}
//입력을 시키는 코딩을 써준다
int boardNumMax = dao.getIntValue("bbs.boardNumMax");
command.setBoardNum(boardNumMax + 1);
command.setIpAddr(request.getRemoteAddr());
dao.insertData("bbs.insertData", command);
return "redirect:/bbs/list.action"; // DB작업후 리다이렉트 가상주소 써놓는다
}//end created()
// 리스트
//list는 form을 쓰는게 아니라 get방식으로 넘어온다. post를 지워도 되는데 그냥 써놓는다
@RequestMapping(value="/bbs/list.action",
method= {RequestMethod.GET,RequestMethod.POST})
public String list(HttpServletRequest request) throws Exception{
HttpSession session = request.getSession(); // 세션을 가져온다.
String cp = request.getContextPath();
int numPerPage = 5;
int totalPage = 0;
int totalDataCount = 0;
String pageNum = request.getParameter("pageNum"); //getParameter로 pageNum을 받아냄
// 수정 메소드에서 updateSubmit()에서 보낸 pageNum을 받음
if(pageNum==null) {
pageNum = (String)session.getAttribute("pageNum"); //세션으로 받음
}
session.removeAttribute("pageNum"); // 지워야만 다음에도 계속 쓸수 있다.
int currentPage = 1;
if(pageNum!=null && !(pageNum.equals(""))) {
currentPage = Integer.parseInt(pageNum); //받아온 페이지넘을 지워야만 다음에도 사용 가능하다?
}
// list.jsp에서 검색되어진 searchKey searchValue를 받는다.
String searchKey = request.getParameter("searchKey");
String searchValue = request.getParameter("searchValue");
if(searchValue==null) {
searchKey = "subject";
searchValue = "";
}
if(request.getMethod().equalsIgnoreCase("GET")) { //method가 GET방식으로 왔으면
searchValue = URLDecoder.decode(searchValue,"UTF-8"); //디코더시켜줌
}
// 아이바티스
Map<String,Object> hMap = new HashMap<String,Object>();
hMap.put("searchKey", searchKey);
hMap.put("searchValue", searchValue);
totalDataCount = dao.getIntValue("bbs.dataCount",hMap); // 전체 데이터 개수
// 전체 페이지 개수
if(totalDataCount!=0) {
totalPage = myUtil.getPageCount(numPerPage, totalDataCount);
}
// 삭제했을때 현재페이지가 토탈페이지보다 크면 문제 생길수도있어서
if(currentPage>totalPage) {
currentPage = totalPage;
}
// 게시물의 시작과 끝값
// currentPage 현재 페이지에 따라 나오는 게시물
int start = (currentPage-1)*numPerPage+1; //5페이지->26
int end = currentPage*numPerPage; //5페이지->30
hMap.put("start", start);
hMap.put("end", end);
List<Object> lists = dao.getListData("bbs.listData",hMap); //여기 까지가 리스트구현
int listNum,n = 0;
ListIterator<Object> it = lists.listIterator(); //리스트에 최적화된 리스트이터레이터 그냥 이터레이터써도?
// 일렬번호 구하기
while(it.hasNext()) {
BoardCommand data = (BoardCommand)it.next();
listNum = totalDataCount - (start + n - 1); //일렬번호 구하는 공식
data.setListNum(listNum);
n++;
} //ajax로 방명록 만들땐 content를 띄웠지만 게시판 리스트에선 content를 띄우지 않기때문에 ajax처럼 setcontent하면 오류남
String params = "";
String urlList = "";
String urlArticle ="";
if(!searchValue.equals("")) { //searchValue가 널이아니면
searchValue = URLEncoder.encode(searchValue,"UTF-8");
params = "searchKey=" + searchKey +
"&searchValue=" + searchValue;
}
if(params.equals("")) { //params가 널이면 새로생성
urlList = cp + "bbs/list.action";
urlArticle = cp + "/bbs/article.action?pageNum="+currentPage;
} else { //params가 널이아니면 params
urlList = cp + "bbs/list.action?" + params;
urlArticle = cp + "/bbs/article.action?pageNum=" +
currentPage + "&" + params;
}
request.setAttribute("lists", lists);
request.setAttribute("urlArticle", urlArticle);
request.setAttribute("pageNum", pageNum);
request.setAttribute("totalPage", totalPage);
request.setAttribute("totalDataCount", totalDataCount);
request.setAttribute("pageIndexList",
myUtil.pageIndexList(currentPage, totalPage, urlList));
return "board/list"; // DB작업이없으므로 포워딩 진짜주소
}
// 게시물
@RequestMapping(value="/bbs/article.action",
method= {RequestMethod.GET,RequestMethod.POST})
public String article(HttpServletRequest request) throws Exception {
//검색을 안했을때 boardNum과 pageNum이 넘어옴
int boardNum = Integer.parseInt(request.getParameter("boardNum"));
String pageNum = request.getParameter("pageNum");
// 검색을 했으면 searchKey,value가 같이 넘어옴
String searchKey = request.getParameter("searchKey");
String searchValue = request.getParameter("searchValue");
if(searchValue==null) {
searchKey = "subject";
searchValue = "";
}
if(request.getMethod().equalsIgnoreCase("GET")) {
searchValue = URLDecoder.decode(searchValue,"UTF-8");
}
// 조회수 증가
dao.updateData("bbs.updateHitCount", boardNum);
BoardCommand dto = (BoardCommand)dao.getReadData("bbs.readData",boardNum);
if(dto==null) { //안써줘도되지만 dto값이null이면
return "redirect:/bbs/list.action";
}
int lineSu = dto.getContent().split("\r\n").length; //content의 엔터친 수 = lineSu
dto.setContent(dto.getContent().replaceAll("\r\n", "<br/>")); //엔터를 br로 줄바뀜 적용
// 데이터 넘겨주기 위한 Map
Map<String,Object> hMap = new HashMap<>();
hMap.put("searchKey", searchKey);
hMap.put("searchValue", searchValue);
hMap.put("boardNum", boardNum);
//BoardNum도 넘어가야함
// db에서 searchKey , searchValue , boardNum 읽어온다.
BoardCommand preReadData =
(BoardCommand)dao.getReadData("bbs.preReadData",hMap);
int preBoardNum = 0;
String preSubject = "";
// 다음 글 데이터가 있으면 불러옴
if(preReadData!=null) {
preBoardNum = preReadData.getBoardNum();
preSubject = preReadData.getSubject();
}
BoardCommand nextReadData =
(BoardCommand)dao.getReadData("bbs.nextReadData",hMap);
int nextBoardNum = 0;
String nextSubject = "";
// 이전 글 데이터가 있으면 불러옴
if(nextReadData!=null) {
nextBoardNum = nextReadData.getBoardNum();
nextSubject = nextReadData.getSubject();
}
String params = "pageNum=" + pageNum;
//params에 기본적으로 pageNum이 있고 검색을했다면 searchKey,searchValue도 들어있슴
if(!searchValue.equals("")) {
searchValue = URLEncoder.encode(searchValue,"UTF-8");
params += "&searchKey=" + searchKey;
params += "&searchValue=" + searchValue;
}
//setAttribute로 넘어가는 데이터들
request.setAttribute("dto", dto);
request.setAttribute("preBoardNum", preBoardNum);
request.setAttribute("preSubject", preSubject);
request.setAttribute("nextBoardNum", nextBoardNum);
request.setAttribute("nextSubject", nextSubject);
request.setAttribute("pageNum", pageNum);
request.setAttribute("params", params);
request.setAttribute("lineSu", lineSu);
return "board/article";
}
// 수정 창 띄우기
@RequestMapping(value="/bbs/updated.action",method= {RequestMethod.GET})
public String updateForm(HttpServletRequest request) throws Exception {
// 게시물에서 넘어온 데이터
int boardNum = Integer.parseInt(request.getParameter("boardNum"));
String pageNum = request.getParameter("pageNum"); //
BoardCommand dto = (BoardCommand)dao.getReadData("bbs.readData",boardNum);
if(dto==null) {
return "redirect:/bbs/list.action?pageNum="+pageNum;
}
// 폼창띄우고 데이터 넘기기
request.setAttribute("dto", dto);
request.setAttribute("mode", "update"); // created.jsp 에 mode를 넘긴다.
request.setAttribute("pageNum", pageNum);
return "board/created"; // 수정창만 띄었지 아직 DB 수정을 한게 아니므로 포워딩
}
// 진짜 수정페이지
// 수정은 입력창을 쓰기때문에 넘어가는 방식은 POST방식
@RequestMapping(value="/bbs/updated.action",method= {RequestMethod.POST})
public String updateSubmit(BoardCommand command, HttpServletRequest request) throws Exception { // 수정한 DTO를 넘겨줘야하므로 command 매개변수 추가함
dao.updateData("bbs.updateData", command);
// 세션을 이용하여 pageNum 넘기기
// list()에서 session으로 받음
// HttpSession session = request.getSession();
// session.setAttribute("pageNum", command.getPageNum());
// return "redirect:/bbs/list.action"; // DB작업을 실제로 수행 세션에 올려서 리다이렉트
// http://localhost:8080/spring/bbs/list.action
return "redirect:/bbs/list.action?pageNum=" + command.getPageNum(); // 이방법도 가능
// http://localhost:8080/spring/bbs/list.action?pageNum=1 이방법은 pageNum이 보인다
}
// 삭제는 Get방식
@RequestMapping(value="/bbs/deleted.action",method= {RequestMethod.GET})
public String updateSubmit( HttpServletRequest request) throws Exception { // COMMEND 는 입력 수정 시 필요
// 게시물에서 넘어온 데이터
int boardNum = Integer.parseInt(request.getParameter("boardNum"));
String pageNum = request.getParameter("pageNum");
dao.deleteData("bbs.deleteData", boardNum);
// 세션을 이용하여 pageNum 넘기기
// list()에서 session으로 받음
// HttpSession session = request.getSession();
// session.setAttribute("pageNum", command.getPageNum());
// return "redirect:/bbs/list.action"; // DB작업을 실제로 수행 세션에 올려서 리다이렉트
// http://localhost:8080/spring/bbs/list.action
return "redirect:/bbs/list.action?pageNum=" + pageNum; // 이방법도 가능
// http://localhost:8080/spring/bbs/list.action?pageNum=1 이방법은 pageNum이 보인다
}
}
'BACKEND > 스프링 Spring' 카테고리의 다른 글
[spring3.0] sts 환경세팅 (0) | 2022.03.24 |
---|---|
[spring2.5] 스프링 객체 생성 (0) | 2022.03.23 |
[spring2.5] 스프링 Annotation (0) | 2022.03.23 |
[spring2.5] 스프링 간단한 예제(2) (0) | 2022.03.23 |
[spring2.5] 스프링 간단한 예제 (0) | 2022.03.23 |