
1. Controller(흐름제어)
BoardController
@Controller
public class BoardController {
// 게시글 작성 폼
@RequestMapping(value = "/write", method = RequestMethod.GET, produces = "text/plain;charset=UTF-8")
public String write(Model model, String current) throws Exception {
logger.debug("Controller: write() 입니다.");
model.addAttribute("vo", new BoardVO());
model.addAttribute("current", current);
return "write";
}
// 게시글 작성 처리
@RequestMapping(value = "/writeProc2", method = RequestMethod.POST)
public ModelAndView writeProc2(@ModelAttribute("vo")BoardVO vo, BindingResult bindingResult, String current, MultipartHttpServletRequest request) throws Exception {
logger.debug("Controller: writeProc2() 입니다.");
Criteria cri = new Criteria();
ModelAndView mv = new ModelAndView();
int intValue = 0;
WriteValidator validator = new WriteValidator();
validator.validate(vo,bindingResult);
if (bindingResult.hasErrors()) {
System.out.println("hasErrors");
List<FieldError> errors = bindingResult.getFieldErrors();
for (FieldError error : errors ) {
System.out.println (error.getField() + " 는 " + error.getDefaultMessage());
if(error.getDefaultMessage().toString().equals("제목을 입력해주세요.")) {
System.out.println(error.getDefaultMessage());
intValue = 1;
break;
} else if(error.getDefaultMessage().toString().equals("내용을 입력해주세요.")) {
System.out.println(error.getDefaultMessage());
intValue = 2;
break;
}
else if(error.getDefaultMessage().toString().equals("제목의 첫글자는 영문 또는 한글이어야합니다.")) {
System.out.println(error.getDefaultMessage());
intValue = 3;
break;
}
else if(error.getDefaultMessage().toString().equals("제목의 길이는 200자를 넘을 수 없습니다.")) {
intValue = 4;
break;
}else if(error.getDefaultMessage().toString().equals("내용의 길이는 300자를 넘을 수 없습니다.")) {
intValue = 5;
break;
}
}
}else {
int titlego = boardService.checkTitle(vo);
//댓글허용 체크박스 체크 안할경우 값 set해주기
if(vo.getComment_yn() == null || vo.getComment_yn().equals("")) {
vo.setComment_yn("y");
}
if(titlego > 0) { //중복시 //기존 : titlego == 1
intValue = 6;
}else if(titlego == 0){
vo.setCategory(current);
intValue = boardService.writeProc(vo); //성공 시 intValue는 7
}
}
mv.setViewName("write");
mv.addObject("write", vo);
mv.addObject("current", current);
mv.addObject("perPageNum", cri.getPerPageNum());
mv.addObject("intValue", intValue);
return mv;
}
//파일 insert
@ResponseBody
@RequestMapping(value = "/insertFile", produces="application/json")
public void insertFile(FileVO fileVO, MultipartHttpServletRequest request) throws Exception {
logger.debug("Controller: insertFile() 입니다.");
logger.debug(fileVO.toString());
System.out.println(String.valueOf(fileVO.getBseq()));
boardService.insertFile(fileVO);
}
}
2. Service(비즈니스 로직, DB 연동 이외의 작업)
BoardService
public interface BoardService {
//게시글 작성
public int writeProc(BoardVO vo) throws Exception;
//게시글 등록 중복체크
public int checkTitle(BoardVO vo) throws Exception;
//파일 저장
public FileVO saveFile(MultipartFile multipartFile, FileVO fileVO) throws Exception;
//file data insert
public void insertFile(FileVO fileVO) throws Exception;
}
BoardServiceImpl
@Service("BoardService")
public class BoardServiceImpl implements BoardService {
@Autowired
BoardDao boardDao;
@Autowired
@Qualifier("fileUtils")
private FileUtils fileUtils;
//게시글 목록, 검색, 페이징
@Override
public List<BoardVO> listAllSearch(Criteria cri) throws Exception {
// TODO Auto-generated method stub
System.out.println("Service: listAll(option, keyword) 입니다.");
return boardDao.listAllSearch(cri);
}
//페이징 전체 목록 개수
@Override
public int countPostListSearch(Criteria cri) throws Exception {
// TODO Auto-generated method stub
return boardDao.countPostListSearch(cri);
}
//게시글 작성
@Override
public int writeProc(BoardVO vo) throws Exception { //, HttpServletRequest request
// TODO Auto-generated method stub
int boardSeq = 0;
FileVO fileVO = new FileVO();
//파일이 있다면 서버에 저장
if(vo.getP_file().getSize() != 0){
System.out.println("BoardServiceImple====saveFile");
fileVO = saveFile(vo.getP_file(), fileVO);
//db에 insert할 originalFileName을 boardVO에 set
//vo.setFile(vo.getP_file().getOriginalFilename());
}else{
vo.setFile(null);
}
System.out.println("BoardServiceImple=============originalFileName : "+ fileVO.getP_file());
//게시글 insert
boardDao.writeProcInsert(vo);
// 방금 작성한 글의 번호 출력 : keyProperty 속성
boardSeq = vo.getBoardSeq();
System.out.println("BoardServiceImple=============boardSeq : "+ boardSeq);
//file 정보 insert
if(fileVO.getF_path() != "") { //파일 저장한 적 있으면,
fileVO.setBseq(boardSeq);
boardDao.insertFile(fileVO);
}
return 7; //return 필요 없음.
}
//파일첨부 정보 출력
private void testFile(FileVO fileVO) {
/*MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest)request;
Iterator<String> iterator = multipartHttpServletRequest.getFileNames();
MultipartFile multipartFile = null;
while(iterator.hasNext()){
multipartFile = multipartHttpServletRequest.getFile(iterator.next());
if(fileVO. == false){ */
System.out.println("------------- file start -------------");
System.out.println("bSeq : "+String.valueOf(fileVO.getBseq()));
System.out.println("name : "+fileVO.getP_file());
//System.out.println("filename : "+multipartFile.getOriginalFilename());
System.out.println("storedFileName : "+fileVO.getF_stored_file_name());
System.out.println("size : "+fileVO.getF_size());
System.out.println("-------------- file end --------------\n");
/*}
}*/
}
//게시글 등록 중복체크
@Override
public int checkTitle(BoardVO vo) throws Exception {
int result = boardDao.checkTitle(vo);
return result;
}
//첨부파일 저장
@Override
public FileVO saveFile(MultipartFile multipartFile, FileVO fileVO) throws Exception{
FileVO fileList = fileUtils.parseInsertFileInfo(multipartFile, fileVO);
return fileList;
}
//file insert
@Override
public void insertFile(FileVO fileVO) throws Exception{
//첨부파일 정보 출력
testFile(fileVO);
//첨부파일 정보 db에 insert
boardDao.insertFile(fileVO);
}
}
3. Model(비즈니스 로직, DB 연동 작업)
FileVO(파일 데이터 저장 클래스)
package com.ncomz.sample.dto;
public class FileVO {
private int f_seq;
private String b_seq; //b_seq. 파일 업로드에 사용
private int bseq; //table insert용
private String f_stored_file_name="";
private String p_file=""; //original file name
private long f_size;
private String f_path="";
public int getF_seq() {
return f_seq;
}
public void setF_seq(int f_seq) {
this.f_seq = f_seq;
}
public String getB_seq() {
return b_seq;
}
public void setB_seq(String b_seq) {
this.b_seq = b_seq;
}
public String getF_stored_file_name() {
return f_stored_file_name;
}
public void setF_stored_file_name(String f_stored_file_name) {
this.f_stored_file_name = f_stored_file_name;
}
public String getP_file() {
return p_file;
}
public void setP_file(String p_file) {
this.p_file = p_file;
}
public long getF_size() {
return f_size;
}
public void setF_size(long f_size) {
this.f_size = f_size;
}
public String getF_path() {
return f_path;
}
public void setF_path(String f_path) {
this.f_path = f_path;
}
public int getBseq() {
return bseq;
}
public void setBseq(int bseq) {
this.bseq = bseq;
}
@Override
public String toString() {
return "FileVO [f_seq=" + f_seq + ", b_seq=" + b_seq + ", bseq=" + bseq + ", f_stored_file_name="
+ f_stored_file_name + ", p_file=" + p_file + ", f_size=" + f_size + ", f_path=" + f_path + "]";
}
}
BoardDao
public interface BoardDao {
public int writeProc(BoardVO vo) throws Exception;
public void writeProcInsert(BoardVO vo) throws Exception;
public int checkTitle(BoardVO vo) throws Exception;
public void insertFile(FileVO fileVO) throws Exception;
public void updateFile(FileVO fileVO) throws Exception;
}
BoardDaoImpl
@Repository
public class BoardDaoImpl implements BoardDao {
SqlSession sqlSession;
//게시글 작성
@Override
public int writeProc(BoardVO vo) throws Exception {
// TODO Auto-generated method stub
return sqlSession.selectOne("com.ncomz.sample.dao.BoardDao.writeProc", vo);
}
@Override
public void writeProcInsert(BoardVO vo) throws Exception {
// TODO Auto-generated method stub
sqlSession.insert("com.ncomz.sample.dao.BoardDao.writeProcInsert", vo);
}
//게시글 작성- 첨부파일 db등록
@Override
public void insertFile(FileVO fileVO) throws Exception {
sqlSession.insert("com.ncomz.sample.dao.BoardDao.insertFile", fileVO);
}
//게시글 등록 중복체크
@Override
public int checkTitle(BoardVO vo) throws Exception {
int result = sqlSession.selectOne("checkTitle", vo);
return result;
}
}
BoardDao.xml(SQL문)
<?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.ncomz.sample.dao.BoardDao">
<!-- 게시글 작성 -->
<select id="writeProc" resultType="int" parameterType="com.ncomz.sample.dto.BoardVO">
SELECT
count(*) AS count
FROM
TB_JMJ_BOARD
WHERE
title = #{title}
</select>
<insert id="writeProcInsert" parameterType="com.ncomz.sample.dto.BoardVO" useGeneratedKeys="true" keyProperty="boardSeq">
INSERT INTO TB_JMJ_BOARD(
title,
content,
category,
register_date,
hit,
comment_yn,
delete_yn,
userSeq
) VALUES (
#{title},
#{content},
#{category},
now(),
0,
#{comment_yn},
'n',
#{userSeq}
)
</insert>
<!-- 게시글 등록-첨부파일 등록 -->
<insert id="insertFile">
INSERT INTO TB_JMJ_FILE(
boardSeq,
NAME,
SIZE,
PATH,
STORED_FILE_NAME
) VALUES (
#{bseq},
#{p_file},
#{f_size},
#{f_path},
#{f_stored_file_name}
)
</insert>
<!-- 게시글 등록 중복체크 -->
<select id="checkTitle" resultType="int">
SELECT
COUNT(*)
FROM
TB_JMJ_BOARD
WHERE
title = #{title}
</select>
</mapper>
4. View(화면)
Write.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=UTF-8");
int sessionSeq = (Integer) session.getAttribute("sessionSeq");
String sessionName = (String) session.getAttribute("sessionName");
%>
<html>
<head>
<title>목록</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<script
src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
<script type="text/javascript">
$(document).ready(function() {
//탭 메뉴 색 변경
if ('${current}' == 'dance') {
$('#currentDashboard').removeClass('current');
$('#currentDance').css({
"background-color" : "#2baae1",
"color" : "#222"
});
} else if ('${current}' == 'movie') {
$('#currentDashboard').removeClass('current');
$('#currentMovie').css({
"background-color" : "#2baae1",
"color" : "#222"
});
}
if ('${intValue}' == '1') {
alert("제목은 필수입니다.");
return;
} else if ('${intValue}' == '2') {
alert("내용은 필수입니다.");
return;
} else if ('${intValue}' == '3') {
alert("제목의 첫글자는 영문 또는 한글이어야합니다.");
return;
} else if ('${intValue}' == '4') {
alert("제목의 길이는 200자를 넘을 수 없습니다.");
return;
} else if ('${intValue}' == '5') {
alert("내용의 길이는 300자를 넘을 수 없습니다.");
return;
} else if ('${intValue}' == '6') {
alert("제목이 중복되었습니다.");
return;
} else if ('${intValue}' == '7') {
alert("등록되었습니다.");
location.href = "list?current=${current}";
}
});
function CK() {
var checkComment = document.getElementById("checkComment").checked;
if (checkComment) {
document.getElementById("comment_yn").value = 'y';
} else {
document.getElementById("comment_yn").value = 'n';
}
}
</script>
<style type="text/css">
.container {
padding-top: 10px;
}
table {
font-family: "Lato", "sans-serif";
font-size: 12px;
width: 60%;
border-collapse: collapse;
margin-top: 10px;
table-layout: fixed;
}
th {
width: 100px;
height: 25px;
text-align: center;
background-color: #2baae1;
color: white;
}
td {
height: 25px;
}
textarea {
width: 100%;
}
input[type="text"], input[type="password"] {
background-color: transparent;
border: 0 solid black;
text-align: center;
}
</style>
</head>
<body>
<jsp:include page="/WEB-INF/views/header.jsp" flush="false" />
<form:form method="post" modelAttribute="vo" name="writeProc" id="writeProc" action="writeProc2" enctype="multipart/form-data">
<div align="center" class="container">
<table border="1">
<tr>
<th>* 제목 </th>
<td>
<form:input class="inputText" name="title" id="title" placeholder="제목을 입력하세요." value="${write.title}" path="title" maxlength="100" />
</td>
<th>댓글 사용 여부</th>
<td>
<input type="hidden" name="comment_yn" id="comment_yn" />
<input type="checkbox" name="checkComment" id="checkComment" checked onclick="CK()" />
</td>
</tr>
<tr>
<th>* 작성자</th>
<td>
<%=sessionName%>
<input type="hidden" name="userSeq" id="userSeq" value="<%=sessionSeq%>">
</td>
<th>등록일</th>
<td>
<jsp:useBean id="now" class="java.util.Date" />
<fmt:formatDate value="${now}" pattern="yyyy/MM/dd a hh:mm:ss" var="today" />
<c:out value="${today}" />
</td>
</tr>
<tr>
<td colspan="4">
<form:textarea name="content" id="content" rows="12" cols="80" placeholder="* 내용을 입력하세요. " path="content"></form:textarea>
</tr>
<tr>
<th>첨부파일</th>
<td colspan="3">
<!-- 첨부파일 객체 추가, 처리 추가 -->
<input type="file" name="p_file" id="p_file" placeholder="첨부파일" accept=".gif, .jpeg, .jpg, .png">
<input type="hidden" name="checkTitle" id="checkTitle" />
</td>
</table>
</div>
<table align="center">
<tr align="right">
<td>
<input type="submit" value="확인" />
<input type="hidden" name="current" value="${current}">
<input type="button" value="취소" onclick="location.href='/list?current=${current}'">
</td>
</tr>
</table>
</form:form>
</body>
</html>
5. Validation
WriteValidator
public class WriteValidator implements Validator {
@Override
public boolean supports(Class<?> arg0) {
// 검증할 객체의 클래스 타입 정보
return BoardVO.class.isAssignableFrom(arg0);
}
@Override
public void validate(Object obj, Errors errors) {
BoardVO vo = (BoardVO)obj;
String inputTitle = vo.getTitle();
if(inputTitle == null || inputTitle.trim().isEmpty() ) {
ValidationUtils.rejectIfEmpty(errors, "title", "titleRequired", "제목을 입력해주세요.");
}else {
//첫글자 영문, 한글 체크
boolean Eng = false;
final char firstChar = inputTitle.charAt(0);
//유니코드 값으로 돌려줌
final int firstCharCode = inputTitle.codePointAt(0);
if (isEng(firstChar) == true || iskor(firstCharCode) == true ) {
Eng = true;
} else {
errors.rejectValue("title", "titleFirstCharisEngORKor" , "제목의 첫글자는 영문 또는 한글이어야합니다.");
}
}
if(inputTitle.length() > 200) {
//제목 길이 체크
errors.rejectValue("title", "titleLengthMax", "제목의 길이는 200자를 넘을 수 없습니다.");
}
String inputContent = vo.getContent();
if(inputContent == null || inputContent.trim().isEmpty() ) {
//내용 null 체크
ValidationUtils.rejectIfEmpty(errors, "content", "contentRequired","내용을 입력해주세요.");
}
if(inputContent.length() > 300) {
//내용 길이 체크
errors.rejectValue("content", "contentLengthMax", "내용의 길이는 300자를 넘을 수 없습니다.");
}
}//validate
public static boolean isEng(char firstChar) {
return (firstChar >= 'A' && firstChar <= 'Z') || (firstChar >= 'a' && firstChar <= 'z');
}
public static boolean iskor(int firstCharCode) {
return (firstCharCode > 0x3130 && firstCharCode < 0x318F) || (firstCharCode>= 0xAC00 && firstCharCode <= 0xD7A3) ;
}
}
6. 환경설정
root-context.xml
<!-- 첨부파일 - MultipartResolver 설정 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="100000000" />
<property name="maxInMemorySize" value="100000000" />
<property name="defaultEncoding" value="utf-8" />
</bean>
pom.xml
<!-- 첨부파일 업로드 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.2</version>
</dependency>
web.xml
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.PNG</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.png</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.JPEG</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpeg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.JPG</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.GIF</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.gif</url-pattern>
</servlet-mapping>'스프링(Spring) > 게시판 만들기' 카테고리의 다른 글
| [Spring 게시판] 수정 (0) | 2020.03.13 |
|---|---|
| [Spring 게시판] 상세보기(댓글) (0) | 2020.03.12 |
| [Spring 게시판] 목록(검색, 페이징, 정렬, 게시글 수, 말줄임표, 마우스오버 시 전체 제목, 등록자 표시) (0) | 2020.03.12 |
| [Spring 게시판] 대시보드 화면(탭메뉴, TOP5, 주간접속통계) (0) | 2020.03.12 |
| [Spring 게시판] 로그인(Session, Validation) (0) | 2020.03.12 |
댓글