-
static/js => member.password.js
-
views/member=>memberChangePassword.jsp 내용추가
-
resources/messages => validation.properties 내용추가
-
MemberController.java 수정
-
resultAlert.jsp
-
Appconfig.java 내용추가
-
table.sql 새로운 테이블 생성
-
kr.spring.board.vo => BoardVO
-
kr.spring.board.dao => BoardMapper
-
kr.spring.board.service => BoardService
-
kr.spring.board.service => BoardServiceImpl
-
kr.spring.board.controller => BoardController
-
WEB-INF/tiles-def => board.xml
-
-
/WEB-INF/views/board=>boardCSS.jsp
-
static/css => board.css
-
/WEB-INF/views/board=>boardList.jsp
-
AppConfig
-
BoardController 내용추가
-
board.xml 내용추가
-
boardWrite.jsp
-
webapp => upload
-
FileUtil.java 내용추가
-
BoardMapper.xml
-
BoardserviceImpl.java
-
BoardController.java
-
message=>validation.properties
-
application.yml 추가설정
-
FileUtil에 설정을 하나 빼먹어서 upload 폴더에 파일이 업로드가 안됨.
-
BoardMapper.xml
-
-
카테고리가 유효성처리가 안되는 문제를 해결
-
BoardVo 수정
-
validation.properties 수정
-
코드 실행순서
static/js => member.password.js
$(function(){
/*-------------------
* 비밀번호 변경 체크
*-------------------*/
$('#passwd').keyup(function(){
if($('#confirm_passwd').val() != '' &&
$('#confirm_passwd').val() != $(this).val()){
$('#message_password').text('비밀번호 불일치').css('color','red');
} else if ($('#confirm_passwd').val() != '' &&
$('#confirm_passwd').val() == $(this).val()){
$('#message_password').text('비밀번호 일치').css('color','#000');
}
});
$('#confirm_passwd').keyup(function(){
if($('#passwd').val() != '' &&
$('#passwd').val() != $(this).val()){
$('#message_password').text('비밀번호 불일치').css('color','red');
} else if ($('#passwd').val() != '' &&
$('#passwd').val() == $(this).val()){
$('#message_password').text('비밀번호 일치').css('color','#000');
}
});
$('#member_change').submit(function(){
if($('#now_passwd').val().trim() == ''){
alert('현재 비밀번호를 입력하세요');
$('#now_passwd').val('').focus();
return false;
}
if($('#passwd').val().trim() == ''){
alert('새 비밀번호를 입력하세요');
$('#passwd').val('').focus();
return false;
}
if($('#confirm_passwd').val().trim() == ''){
alert('새 비밀번호 확인을 입력하세요');
$('#confirm_passwd').val('').focus();
return false;
}
if($('#passwd').val() != $('#confirm_passwd').val()){
$('#message_password').text('비밀번호 불일치').css('color','red');
return false;
}
});
});
views/member=>memberChangePassword.jsp 내용추가
<!-- nav_mypage.jsp에 jquery-3.7.1.min은 이미 호출되어있어서 여기서 호출안해도됨 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/member.password.js"></script>
resources/messages => validation.properties 내용추가
Pattern.captcha_chars=캡챠 문자는 필수
invalidCaptcha=캡챠 문자 불일치
MemberController.java 수정
어제했던 requestHeaders2를 지우고 그냥 requestHeaders를 사용하였다.(굳이 명시하지않음)
//===========캡챠 문자 체크 시작 ==========//
String code = "1";//키 발급 0, 캡챠 이미지 비교시 1로 세팅
//캡챠 키 발급시 받은 키값
String key = (String)session.getAttribute("captcha_key");
//사용자가 입력한 캡챠 이미지 글자값
String value = memberVO.getCaptcha_chars();
String apiURL = "https://openapi.naver.com/v1/captcha/nkey?code="+code + "&key="+key+"&value="+value;
Map<String,String> requestHeaders = new HashMap<String,String>();
requestHeaders.put("X-Naver-Client-Id","Cc1wS4rT2GXzIGRPGXca");
requestHeaders.put("X-Naver-Client-Secret","AHEsY00rCk");
String responseBody = CaptchaUtil.get(apiURL, requestHeaders);
log.debug("<<캡챠 결과>> : "+responseBody); //이 디버그 결과는 json 객체로 만들기 떄문에 json 결과로 나온다.
JSONObject jObject = new JSONObject(responseBody);
boolean captcha_result = jObject.getBoolean("result");
if(!captcha_result) {
result.rejectValue("captcha_chars","invalidCaptcha");
return formChangePassword();
}
//===========캡챠 문자 체크 끝 ==========//
MemberVO user = (MemberVO)session.getAttribute("user");
memberVO.setMem_num(user.getMem_num());
MemberVO db_member = memberService.selectMember(memberVO.getMem_num());
//폼에서 전송한 현재 비밀번호와 DB에서 읽어온 비밀번호가 일치 여부 체크
if(!db_member.getPasswd().equals(memberVO.getNow_passwd())) {//불일치할 때
result.rejectValue("now_passwd","invalidPassword");
return formChangePassword();
}
//비밀번호 수정
memberService.updatePassword(memberVO);
//설정되어 있는 자동로그인 기능 해제(모든 브라우저에 설정된 자동로그인 해제) -> 비밀번호가 바뀌면 자동로그인이 되어져있는걸 해제한다.
memberService.deleteAu_id(memberVO.getMem_num());
//View에 표시할 메시지
model.addAttribute("message","비밀번호 변경 완료(*재접속시 설정되어 있는 자동로그인 기능 해제)");
model.addAttribute("url",request.getContextPath()+"/member/myPage");
//모든게 완료되면 여기로 넘어감.
return "common/resultAlert";
resultAlert.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<script>
alert('${message}');
location.href='${url}';
</script>



Appconfig.java 내용추가
.addPathPatterns("/member/changePassword");; //추가
@Override
public void addInterceptors(InterceptorRegistry registry) {
//LoginCheckInterceptor 설정
registry.addInterceptor(loginCheck).addPathPatterns("/member/myPage")
.addPathPatterns("/member/update")
.addPathPatterns("/member/changePassword");;
table.sql 새로운 테이블 생성
--게시판
create table spboard(
board_num number not null,
category char(1) not null,
title varchar2(90) not null,
content clob not null,
hit number(8) default 0 not null,
reg_date date default sysdate not null,
modify_date date,
filename varchar2(400),
ip varchar2(40) not null,
mem_num number not null,
constraint spboard_pk primary key (board_num),
constraint spboard_fk foreign key (mem_num)
references spmember (mem_num)
);
create sequence spboard_seq;
kr.spring.board.vo => BoardVO
package kr.spring.board.vo;
import java.sql.Date;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;
import org.springframework.web.multipart.MultipartFile;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class BoardVO {
private long board_num; //게시판번호
@NotBlank
private String title; //제목
@Size(min=1,max=1)
private String category; //카테고리 분야
@NotEmpty
private String content; //내용
private int hit; //조회수
private Date reg_date; //등록일
private Date modify_date; //수정일
private MultipartFile upload; //파일
private String filename; //파일명
private String ip; //ip주소
private long mem_num; //회원번호
private String id; //id
private String nick_name; //별명
private int re_cnt; //댓글 개수
private int fav_cnt; //좋아요 개수
}
kr.spring.board.dao => BoardMapper
package kr.spring.board.dao;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Mapper;
import kr.spring.board.vo.BoardVO;
@Mapper
public interface BoardMapper {
//부모글
public List<BoardVO> selectList(Map<String,Object>map);
public Integer selectRowCount(Map<String,Object>map); //Integer나 int나 아무거로 해도됨
public void insertBoard(BoardVO board);
public BoardVO selectBoard(Long board_num);
public void updateHit(Long board_num);
public void updateBoard(BoardVO board);
public void deleteBoard(Long board_num);
public void deleteFile(Long board_num);
//부모글 좋아요
//댓글
//댓글 좋아요
//답글(대댓글)
}
kr.spring.board.service => BoardService
package kr.spring.board.service;
import java.util.List;
import java.util.Map;
import kr.spring.board.vo.BoardVO;
public interface BoardService {
//부모글
public List<BoardVO> selectList(Map<String,Object>map);
public Integer selectRowCount(Map<String,Object>map); //Integer나 int나 아무거로 해도됨
public void insertBoard(BoardVO board);
public BoardVO selectBoard(Long board_num);
public void updateHit(Long board_num);
public void updateBoard(BoardVO board);
public void deleteBoard(Long board_num);
public void deleteFile(Long board_num);
}
kr.spring.board.service => BoardServiceImpl
package kr.spring.board.service;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import kr.spring.board.dao.BoardMapper;
import kr.spring.board.vo.BoardVO;
@Service
@Transactional
public class BoardServiceImpl implements BoardService{
@Autowired
BoardMapper boardMapper;
@Override
public List<BoardVO> selectList(Map<String, Object> map) {
// TODO Auto-generated method stub
return null;
}
@Override
public Integer selectRowCount(Map<String, Object> map) {
// TODO Auto-generated method stub
return null;
}
@Override
public void insertBoard(BoardVO board) {
// TODO Auto-generated method stub
}
@Override
public BoardVO selectBoard(Long board_num) {
// TODO Auto-generated method stub
return null;
}
@Override
public void updateHit(Long board_num) {
// TODO Auto-generated method stub
}
@Override
public void updateBoard(BoardVO board) {
// TODO Auto-generated method stub
}
@Override
public void deleteBoard(Long board_num) {
// TODO Auto-generated method stub
}
@Override
public void deleteFile(Long board_num) {
// TODO Auto-generated method stub
}
}
kr.spring.board.controller => BoardController
package kr.spring.board.controller;
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.RequestParam;
import kr.spring.board.service.BoardService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
public class BoardController {
@Autowired
private BoardService boardService;
/*=======================
* 게시판 목록
*=======================*/
@GetMapping("/board/list")
public String getList(@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "1") int order,
@RequestParam(defaultValue = "") String category, //나중에 변경될 코드 null값이 나오지않게 하기위해 임시로해둠
String keyfield, String keyword, Model model) {
log.debug("<<게시판 목록 - category>> :"+category);
log.debug("<<게시판 목록 - order>> :"+order); //정렬
return "boardList";
}
}
WEB-INF/tiles-def => board.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
"http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
<definition name="boardList" extends="main">
<put-attribute name="title" value="게시판 목록"/>
<put-attribute name="css" value="/WEB-INF/views/board/boardCSS.jsp"/>
<put-attribute name="body" value="/WEB-INF/views/board/boardList.jsp"/>
</definition>
</tiles-definitions>
/WEB-INF/views/board=>boardCSS.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/board.css" type="text/css">
static/css => board.css
공통 css인 common.css의 '게시판 글상세'와 '게시판 글 수정' 주석아래의 css들을 잘라서 가져오고 추가적으로 명시
@charset "UTF-8";
/* 게시판 목록
---------------------*/
form#search_form #order{
height:32px;
}
/* 게시판 폼
---------------------*/
/*CKEditor 사용시 등록, 수정폼*/
form#register_form, form#update_form{
padding:0 0 10px 0;
width:800px;
}
form#register_form ul, form#update_form ul{
padding:20px;
}
form#register_form input[type="text"], form#update_form input[type="text"]{
width:759px;
margin-bottom: 10px;
}
.ck-editor__editable_inline{/* CKEditor 전용 */
min-height:250px;
}
/* 게시판 글상세
---------------------*/
ul.detail-info li{
display:inline-block;
}
.detail-img{
max-width:500px;
}
ul.detail-sub{
margin:0;
padding:0;
}
ul.detail-sub li{
display:inline-block;
width:49%;
height:50px;
vertical-align:middle;
}
ul.detail-sub li:first-child img{
vertical-align:middle;
}
ul.detail-sub li:last-child{
text-align:right;
line-height:250%;
}
#output_fav{
cursor:pointer;
}
div#reply_div{
padding:5px 10px 40px 10px;
margin-top:10px;
background-color:#EEEEEE;
}
form#re_form{
width:650px;
border:none;
}
span.re-title{
color:#000;
font-size:12pt;
line-height:200%;
}
span.letter-count{
font-size:10pt;
color:#999;
}
textarea.rep-content{
width:90%;
height:50px;
margin:10px;
}
div#re_first, div#mre_first{
float:left;
width:70%;
padding-left:15px;
margin-bottom:10px;
}
div#re_second, div#mre_second{
float:left;
width:19%;
margin-bottom:10px;
}
div#loading{
text-align:center;
}
div.paging-button{
text-align:right;
}
div#output{
clear:both;
}
form#mre_form{
border:none;
margin:5px;
}
/* 게시판 글 수정
---------------------*/
#file_detail{
margin:5px 0 0 130px;
}
/WEB-INF/views/board=>boardList.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!-- 게시판 목록 시작 -->
<div class="page-main">
<h2>게시판 목록</h2>
<div class="align-right">
<c:if test="${!empty user}">
<input type="button" value="글쓰기" onclick="location.href='write'">
</c:if>
</div>
</div>
<!-- 게시판 목록 끝 -->
AppConfig
xml 과 jsp와 연결해주고 추가로 로그인 체크 인터셉터를 설정해준다.
@Bean
public loginCheckInterceptor interceptor2() {
loginCheck = new loginCheckInterceptor();
return loginCheck;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
//LoginCheckInterceptor 설정
registry.addInterceptor(loginCheck).addPathPatterns("/member/myPage")
.addPathPatterns("/member/update")
.addPathPatterns("/member/changePassword")
.addPathPatterns("/member/delete")
.addPathPatterns("/board/write")
.addPathPatterns("/board/update")
.addPathPatterns("/board/delete");
}
@Bean
public TilesConfigurer tilesConfigurer() {
final TilesConfigurer configurer =
new TilesConfigurer();
//XML 설정 파일 경로 지정
configurer.setDefinitions(new String[] {
"/WEB-INF/tiles-def/main.xml",
"/WEB-INF/tiles-def/member.xml",
"/WEB-INF/tiles-def/board.xml"
});
configurer.setCheckRefresh(true);
return configurer;
}
header.jsp
<a href="${pageContext.request.contextPath}/board/list">게시판</a>

BoardController 내용추가
//자바빈(VO) 초기화
@ModelAttribute
public BoardVO initCommand() {
return new BoardVO();
}
/*=======================
* 게시판 글쓰기
*=======================*/
//등록 폼 호출
@GetMapping("/board/write")
public String form() {
return "boardWrite";
}
//등록 폼에서 전송된 데이터 처리
board.xml 내용추가
<definition name="boardWrite" extends="main">
<put-attribute name="title" value="게시판 글쓰기"/>
<put-attribute name="css" value="/WEB-INF/views/board/boardCSS.jsp"/>
<put-attribute name="body" value="/WEB-INF/views/board/boardWrite.jsp"/>
</definition>
boardWrite.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!-- 게시판 글쓰기 시작 -->
<div class="page-main">
<h2>글쓰기</h2>
<form:form action="write" id="board_register"
enctype="multipart/form-data"
modelAttribute="boardVO">
<ul>
<li>
<form:label path="category">분류</form:label>
<form:select path="category">
<!-- 이 옵션을 기본 선택으로 지정해둔 코드 -->
<option disabled="disabled" selected>선택하세요</option>
<form:option value="1">자바</form:option>
<form:option value="2">데이터베이스</form:option>
<form:option value="3">자바스크립드</form:option>
<form:option value="4">기타</form:option>
</form:select>
<form:errors path="category" cssClass="error-color"/>
</li>
<li>
<form:label path="title">제목</form:label>
<form:input path="title"/>
<form:errors path="title" cssClass="error-color"/>
</li>
<li>
<form:label path="content">내용</form:label>
<form:textarea path="content"/>
<form:errors path="content" cssClass="error-color"/>
</li>
<li>
<form:label path="upload">파일 업로드</form:label>
<input type="file" name="upload" id="upload">
</li>
</ul>
<div class="align-center">
<form:button class="default-btn">전송</form:button>
<input type="button" value="목록"
class="default-btn"
onclick="location.href='list'">
</div>
</form:form>
</div>
<!-- 게시판 글쓰기 끝 -->

webapp => upload
업로드되는 파일의 위치이다.
FileUtil.java 내용추가
화면 폼이 나왔으니까 이제 내용(파일 등)을 전송하는 법 작성
내용은 upload 폴더로 이동한다.
>> 전송(insert)작업을 하기전에 FileUtil에서 파일 작업을 먼저해야됨.
//업로드 상대 경로
private static final String UPLOAD_PATH = "/upload";
//파일 업로드 처리
public static String createFile(HttpServletRequest request,
MultipartFile file) throws IllegalStateException,IOException{
//컨텍스트 루트상의 절대 경로 구하기
String path = request.getServletContext().getRealPath(UPLOAD_PATH);
String filename = null;
if(file!=null && !file.isEmpty()) {
//파일명이 중복되지 않도록 파일명 변경
//원래 파일명을 보존하지 않을경우
filename = UUID.randomUUID()+
file.getOriginalFilename()
.substring(file.getOriginalFilename()
.lastIndexOf("."));
// _(언더바) 이후에 원래 파일명을 보존할 경우
//filename = UUID.randomUUID()+"_"+file.getOriginalFilename();
}
return filename;
}
//파일 삭제
public static void removeFile(HttpServletRequest request, String filename) {
if(filename !=null) {
//컨텍스트 루트상의 절대 경로 구하기
String path = request.getServletContext().getRealPath(UPLOAD_PATH);
File file = new File(path+"/"+filename);
if(file.exists()) file.delete();
}
}
BoardMapper.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="kr.spring.board.dao.BoardMapper">
<!-- 글쓰기 -->
<insert id="insertBoard" parameterType="boardVO">
INSERT INTO spboard(
board_num,
category,
title,
content,
filename,
ip,
mem_num)
VALUES(
spboard_seq.nextval,
#{category},
#{title},
#{content},
#{filename},
#{ip},
#{mem_num})
</insert>
</mapper>
BoardserviceImpl.java
@Override
public void insertBoard(BoardVO board) {
boardMapper.insertBoard(board);
}
BoardController.java
//등록 폼에서 전송된 데이터 처리
@PostMapping("/board/write")
public String submit(@Valid BoardVO boardVO,
BindingResult result,
HttpServletRequest request,
HttpSession session,
Model model) throws IllegalStateException,IOException {
log.debug("<<게시판 글 저장>> : "+boardVO);
//유효성 체크 결과 오류가 있으면 폼 호출
if(result.hasErrors()) {
return form();
}
//오류가 없으면 정보처리를 함.
//회원번호 세팅
MemberVO vo = (MemberVO)session.getAttribute("user");
boardVO.setMem_num(vo.getMem_num());
//ip셋팅
boardVO.setIp(request.getRemoteAddr());
//파일 업로드
boardVO.setFilename(FileUtil.createFile(request,boardVO.getUpload())); //여길 지나면 업로드가 된거임
//글쓰기
boardService.insertBoard(boardVO);
//View 메시지 처리
model.addAttribute("message","성공적으로 글이 등록되었습니다.");
model.addAttribute("url",request.getContextPath()+"/board/list");
return "common/resultAlert";
}
message=>validation.properties
VO에서 NotBlak 같은 것을 설정 했을 때 나올 값들 설정
#게시판
Size.category=분류를 선택하세요
NotBlank.title=제목은 필수
NotEmpty.content=내용은 필수
application.yml 추가설정
servlet:
multipart:
max-file-size: 50MB #파일 한 개당 최대 사이즈
max-request-size: 200MB #요청당 최대 파일 크기
tomcat:
max-http-form-post-size: 200MB #톰캣에서 허용하는 파일 업로드 사이즈




FileUtil에 설정을 하나 빼먹어서 upload 폴더에 파일이 업로드가 안됨.
//upload 폴더로 업로드한 파일이 이동되도록 하는 코드
file.transferTo(new File(path+"/"+filename));
다시 SQL에 있는 값을 삭제하고 똑같이 업로드하면 upload안에 업로드한 파일이 들어간다.



제목과 내용은 not null이지만 파일 null 허용이다. 그치만 파일을 보내지않으면 에러가난다.
why?
SQL에 null을 허용했다고 해도 mybatis 자체에서 null을 허용하지 않기 때문에 에러가난다.
그러므로 이 에러를 나지않게 설정을 추가로 해줘야된다.
BoardMapper.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="kr.spring.board.dao.BoardMapper">
<!-- 글쓰기 -->
<insert id="insertBoard" parameterType="boardVO">
INSERT INTO spboard(
board_num,
category,
title,
content,
filename,
ip,
mem_num)
VALUES(
spboard_seq.nextval,
#{category},
#{title},
#{content},
#{filename,jdbcType=VARCHAR},
#{ip},
#{mem_num})
</insert>
</mapper>
jdbcType=VARCHAR를 4번째 열인 filename에 적어준 뒤 다시 실행하여 파일을 빼고 보내면 에러없이 전달된다.

카테고리가 유효성처리가 안되는 문제를 해결
BoardVo 수정
@NotBlank
private String category; //카테고리 분야
validation.properties 수정
#게시판
NotBlank.category=분류를 선택하세요
NotBlank.title=제목은 필수
NotEmpty.content=내용은 필수

코드 실행순서
>>SQL 만들기
>>VO 객체지정
>>BoardMapper 인터페이스로 dao지정
>>BoardService 인터페이스로 mapper의 서비스 네트워크 지정
>> BoardServiceImpl 클래스를 생성해서 service의 호출을 돕는다.
>> BoardController 클래스를 생성해서 연결 및 화면구현을 돕는다.
백앤드 쪽이 세팅이 끝났으면 프론트앤드 쪽을 세팅한다.
>>모든 화면에서 다 보이는 tiles의 board.xml을 설정한다.
>>tiles에서 값으로 저장한 jsp들을 만든다.
>>boardcss.jsp를 호출해서 꾸며주는 css 파일을 만든다.
>>css가 끝나면 jsp를 설정해준다
>>Appconfig에서 xml 과 jsp와 연결해주고 추가로 로그인 체크 인터셉터를 설정해준다.
>> header.jsp 에서 링크 설정을 해준다.
[헤더에 있는 board/list 링크를 누르면 controller에 있는 getMapping 링크가 연결되면서 return 값으로 boardList를 보냄.
그러면 board.xml에서 name값으로 boardList를 받고 데피니션 안에 있는 링크값들을 화면에 뿌려줌.
링크값들 역시 jsp파일들이기 때문에 jsp파일 안에 내용들이 화면에 뿌려짐 ]
<layout_basic=>header => controller => xml => jsp>
>>Controller에서 게시판 글쓰기 등록 폼을 만든다.
>> 컨트롤러에서 설정한 return 값을 board.xml에서 데피니션을 만들어준다.
>>xml에서 put-에트리뷰트 한 링크값 jsp를 만든다.
>>만든 jsp의 화면을 만든다.
화면 폼이 나왔으니까 이제 내용(파일 등)을 전송하는 법 작성
내용은 upload 폴더로 이동한다.
>> 전송(insert)작업을 하기전에 FileUtil에서 파일 작업을 먼저해야됨.
>>insert 작업 SQL문의 내용이 길기 때문에 BoardMapper.xml 를 만들어서 BoardMapper.java 대신 사용한다
>>xml에서 작성한 SQL문을 BoardServiceImpl에서 호출을 해준다.
>>BoardServiceImpl에서 전송받은 데이터를 Controller에서 처리한다.(PostMapping)
>>** (미리못한 것들 설정)
VO에서 NotBlak 같은 것을 설정 했을 때 나올 값들 validation.properties 에서 설정
>>application.yml에서 업로드 할 파일 크기 설정 (순서는 상관없고 파일을 사용한다고하면 넣어주면됨)
'쌍용교육(JAVA) > SpringBoot' 카테고리의 다른 글
쌍용교육 -JSP수업 96일차 ch15SpringPage(7) (0) | 2024.07.03 |
---|---|
쌍용교육 -JSP수업 94일차 ch15SpringPage(5) (0) | 2024.07.01 |
쌍용교육 -JSP수업 92일차 ch15SpringPage(3) (1) | 2024.06.27 |
쌍용교육 -JSP수업 91일차 ch15SpringPage(2) (0) | 2024.06.26 |
쌍용교육 -JSP수업 90일차 ch15SpringPage (0) | 2024.06.25 |
static/js => member.password.js
$(function(){
/*-------------------
* 비밀번호 변경 체크
*-------------------*/
$('#passwd').keyup(function(){
if($('#confirm_passwd').val() != '' &&
$('#confirm_passwd').val() != $(this).val()){
$('#message_password').text('비밀번호 불일치').css('color','red');
} else if ($('#confirm_passwd').val() != '' &&
$('#confirm_passwd').val() == $(this).val()){
$('#message_password').text('비밀번호 일치').css('color','#000');
}
});
$('#confirm_passwd').keyup(function(){
if($('#passwd').val() != '' &&
$('#passwd').val() != $(this).val()){
$('#message_password').text('비밀번호 불일치').css('color','red');
} else if ($('#passwd').val() != '' &&
$('#passwd').val() == $(this).val()){
$('#message_password').text('비밀번호 일치').css('color','#000');
}
});
$('#member_change').submit(function(){
if($('#now_passwd').val().trim() == ''){
alert('현재 비밀번호를 입력하세요');
$('#now_passwd').val('').focus();
return false;
}
if($('#passwd').val().trim() == ''){
alert('새 비밀번호를 입력하세요');
$('#passwd').val('').focus();
return false;
}
if($('#confirm_passwd').val().trim() == ''){
alert('새 비밀번호 확인을 입력하세요');
$('#confirm_passwd').val('').focus();
return false;
}
if($('#passwd').val() != $('#confirm_passwd').val()){
$('#message_password').text('비밀번호 불일치').css('color','red');
return false;
}
});
});
views/member=>memberChangePassword.jsp 내용추가
<!-- nav_mypage.jsp에 jquery-3.7.1.min은 이미 호출되어있어서 여기서 호출안해도됨 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/member.password.js"></script>
resources/messages => validation.properties 내용추가
Pattern.captcha_chars=캡챠 문자는 필수
invalidCaptcha=캡챠 문자 불일치
MemberController.java 수정
어제했던 requestHeaders2를 지우고 그냥 requestHeaders를 사용하였다.(굳이 명시하지않음)
//===========캡챠 문자 체크 시작 ==========//
String code = "1";//키 발급 0, 캡챠 이미지 비교시 1로 세팅
//캡챠 키 발급시 받은 키값
String key = (String)session.getAttribute("captcha_key");
//사용자가 입력한 캡챠 이미지 글자값
String value = memberVO.getCaptcha_chars();
String apiURL = "https://openapi.naver.com/v1/captcha/nkey?code="+code + "&key="+key+"&value="+value;
Map<String,String> requestHeaders = new HashMap<String,String>();
requestHeaders.put("X-Naver-Client-Id","Cc1wS4rT2GXzIGRPGXca");
requestHeaders.put("X-Naver-Client-Secret","AHEsY00rCk");
String responseBody = CaptchaUtil.get(apiURL, requestHeaders);
log.debug("<<캡챠 결과>> : "+responseBody); //이 디버그 결과는 json 객체로 만들기 떄문에 json 결과로 나온다.
JSONObject jObject = new JSONObject(responseBody);
boolean captcha_result = jObject.getBoolean("result");
if(!captcha_result) {
result.rejectValue("captcha_chars","invalidCaptcha");
return formChangePassword();
}
//===========캡챠 문자 체크 끝 ==========//
MemberVO user = (MemberVO)session.getAttribute("user");
memberVO.setMem_num(user.getMem_num());
MemberVO db_member = memberService.selectMember(memberVO.getMem_num());
//폼에서 전송한 현재 비밀번호와 DB에서 읽어온 비밀번호가 일치 여부 체크
if(!db_member.getPasswd().equals(memberVO.getNow_passwd())) {//불일치할 때
result.rejectValue("now_passwd","invalidPassword");
return formChangePassword();
}
//비밀번호 수정
memberService.updatePassword(memberVO);
//설정되어 있는 자동로그인 기능 해제(모든 브라우저에 설정된 자동로그인 해제) -> 비밀번호가 바뀌면 자동로그인이 되어져있는걸 해제한다.
memberService.deleteAu_id(memberVO.getMem_num());
//View에 표시할 메시지
model.addAttribute("message","비밀번호 변경 완료(*재접속시 설정되어 있는 자동로그인 기능 해제)");
model.addAttribute("url",request.getContextPath()+"/member/myPage");
//모든게 완료되면 여기로 넘어감.
return "common/resultAlert";
resultAlert.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<script>
alert('${message}');
location.href='${url}';
</script>



Appconfig.java 내용추가
.addPathPatterns("/member/changePassword");; //추가
@Override
public void addInterceptors(InterceptorRegistry registry) {
//LoginCheckInterceptor 설정
registry.addInterceptor(loginCheck).addPathPatterns("/member/myPage")
.addPathPatterns("/member/update")
.addPathPatterns("/member/changePassword");;
table.sql 새로운 테이블 생성
--게시판
create table spboard(
board_num number not null,
category char(1) not null,
title varchar2(90) not null,
content clob not null,
hit number(8) default 0 not null,
reg_date date default sysdate not null,
modify_date date,
filename varchar2(400),
ip varchar2(40) not null,
mem_num number not null,
constraint spboard_pk primary key (board_num),
constraint spboard_fk foreign key (mem_num)
references spmember (mem_num)
);
create sequence spboard_seq;
kr.spring.board.vo => BoardVO
package kr.spring.board.vo;
import java.sql.Date;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;
import org.springframework.web.multipart.MultipartFile;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class BoardVO {
private long board_num; //게시판번호
@NotBlank
private String title; //제목
@Size(min=1,max=1)
private String category; //카테고리 분야
@NotEmpty
private String content; //내용
private int hit; //조회수
private Date reg_date; //등록일
private Date modify_date; //수정일
private MultipartFile upload; //파일
private String filename; //파일명
private String ip; //ip주소
private long mem_num; //회원번호
private String id; //id
private String nick_name; //별명
private int re_cnt; //댓글 개수
private int fav_cnt; //좋아요 개수
}
kr.spring.board.dao => BoardMapper
package kr.spring.board.dao;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Mapper;
import kr.spring.board.vo.BoardVO;
@Mapper
public interface BoardMapper {
//부모글
public List<BoardVO> selectList(Map<String,Object>map);
public Integer selectRowCount(Map<String,Object>map); //Integer나 int나 아무거로 해도됨
public void insertBoard(BoardVO board);
public BoardVO selectBoard(Long board_num);
public void updateHit(Long board_num);
public void updateBoard(BoardVO board);
public void deleteBoard(Long board_num);
public void deleteFile(Long board_num);
//부모글 좋아요
//댓글
//댓글 좋아요
//답글(대댓글)
}
kr.spring.board.service => BoardService
package kr.spring.board.service;
import java.util.List;
import java.util.Map;
import kr.spring.board.vo.BoardVO;
public interface BoardService {
//부모글
public List<BoardVO> selectList(Map<String,Object>map);
public Integer selectRowCount(Map<String,Object>map); //Integer나 int나 아무거로 해도됨
public void insertBoard(BoardVO board);
public BoardVO selectBoard(Long board_num);
public void updateHit(Long board_num);
public void updateBoard(BoardVO board);
public void deleteBoard(Long board_num);
public void deleteFile(Long board_num);
}
kr.spring.board.service => BoardServiceImpl
package kr.spring.board.service;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import kr.spring.board.dao.BoardMapper;
import kr.spring.board.vo.BoardVO;
@Service
@Transactional
public class BoardServiceImpl implements BoardService{
@Autowired
BoardMapper boardMapper;
@Override
public List<BoardVO> selectList(Map<String, Object> map) {
// TODO Auto-generated method stub
return null;
}
@Override
public Integer selectRowCount(Map<String, Object> map) {
// TODO Auto-generated method stub
return null;
}
@Override
public void insertBoard(BoardVO board) {
// TODO Auto-generated method stub
}
@Override
public BoardVO selectBoard(Long board_num) {
// TODO Auto-generated method stub
return null;
}
@Override
public void updateHit(Long board_num) {
// TODO Auto-generated method stub
}
@Override
public void updateBoard(BoardVO board) {
// TODO Auto-generated method stub
}
@Override
public void deleteBoard(Long board_num) {
// TODO Auto-generated method stub
}
@Override
public void deleteFile(Long board_num) {
// TODO Auto-generated method stub
}
}
kr.spring.board.controller => BoardController
package kr.spring.board.controller;
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.RequestParam;
import kr.spring.board.service.BoardService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
public class BoardController {
@Autowired
private BoardService boardService;
/*=======================
* 게시판 목록
*=======================*/
@GetMapping("/board/list")
public String getList(@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "1") int order,
@RequestParam(defaultValue = "") String category, //나중에 변경될 코드 null값이 나오지않게 하기위해 임시로해둠
String keyfield, String keyword, Model model) {
log.debug("<<게시판 목록 - category>> :"+category);
log.debug("<<게시판 목록 - order>> :"+order); //정렬
return "boardList";
}
}
WEB-INF/tiles-def => board.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
"http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
<definition name="boardList" extends="main">
<put-attribute name="title" value="게시판 목록"/>
<put-attribute name="css" value="/WEB-INF/views/board/boardCSS.jsp"/>
<put-attribute name="body" value="/WEB-INF/views/board/boardList.jsp"/>
</definition>
</tiles-definitions>
/WEB-INF/views/board=>boardCSS.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/board.css" type="text/css">
static/css => board.css
공통 css인 common.css의 '게시판 글상세'와 '게시판 글 수정' 주석아래의 css들을 잘라서 가져오고 추가적으로 명시
@charset "UTF-8";
/* 게시판 목록
---------------------*/
form#search_form #order{
height:32px;
}
/* 게시판 폼
---------------------*/
/*CKEditor 사용시 등록, 수정폼*/
form#register_form, form#update_form{
padding:0 0 10px 0;
width:800px;
}
form#register_form ul, form#update_form ul{
padding:20px;
}
form#register_form input[type="text"], form#update_form input[type="text"]{
width:759px;
margin-bottom: 10px;
}
.ck-editor__editable_inline{/* CKEditor 전용 */
min-height:250px;
}
/* 게시판 글상세
---------------------*/
ul.detail-info li{
display:inline-block;
}
.detail-img{
max-width:500px;
}
ul.detail-sub{
margin:0;
padding:0;
}
ul.detail-sub li{
display:inline-block;
width:49%;
height:50px;
vertical-align:middle;
}
ul.detail-sub li:first-child img{
vertical-align:middle;
}
ul.detail-sub li:last-child{
text-align:right;
line-height:250%;
}
#output_fav{
cursor:pointer;
}
div#reply_div{
padding:5px 10px 40px 10px;
margin-top:10px;
background-color:#EEEEEE;
}
form#re_form{
width:650px;
border:none;
}
span.re-title{
color:#000;
font-size:12pt;
line-height:200%;
}
span.letter-count{
font-size:10pt;
color:#999;
}
textarea.rep-content{
width:90%;
height:50px;
margin:10px;
}
div#re_first, div#mre_first{
float:left;
width:70%;
padding-left:15px;
margin-bottom:10px;
}
div#re_second, div#mre_second{
float:left;
width:19%;
margin-bottom:10px;
}
div#loading{
text-align:center;
}
div.paging-button{
text-align:right;
}
div#output{
clear:both;
}
form#mre_form{
border:none;
margin:5px;
}
/* 게시판 글 수정
---------------------*/
#file_detail{
margin:5px 0 0 130px;
}
/WEB-INF/views/board=>boardList.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!-- 게시판 목록 시작 -->
<div class="page-main">
<h2>게시판 목록</h2>
<div class="align-right">
<c:if test="${!empty user}">
<input type="button" value="글쓰기" onclick="location.href='write'">
</c:if>
</div>
</div>
<!-- 게시판 목록 끝 -->
AppConfig
xml 과 jsp와 연결해주고 추가로 로그인 체크 인터셉터를 설정해준다.
@Bean
public loginCheckInterceptor interceptor2() {
loginCheck = new loginCheckInterceptor();
return loginCheck;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
//LoginCheckInterceptor 설정
registry.addInterceptor(loginCheck).addPathPatterns("/member/myPage")
.addPathPatterns("/member/update")
.addPathPatterns("/member/changePassword")
.addPathPatterns("/member/delete")
.addPathPatterns("/board/write")
.addPathPatterns("/board/update")
.addPathPatterns("/board/delete");
}
@Bean
public TilesConfigurer tilesConfigurer() {
final TilesConfigurer configurer =
new TilesConfigurer();
//XML 설정 파일 경로 지정
configurer.setDefinitions(new String[] {
"/WEB-INF/tiles-def/main.xml",
"/WEB-INF/tiles-def/member.xml",
"/WEB-INF/tiles-def/board.xml"
});
configurer.setCheckRefresh(true);
return configurer;
}
header.jsp
<a href="${pageContext.request.contextPath}/board/list">게시판</a>

BoardController 내용추가
//자바빈(VO) 초기화
@ModelAttribute
public BoardVO initCommand() {
return new BoardVO();
}
/*=======================
* 게시판 글쓰기
*=======================*/
//등록 폼 호출
@GetMapping("/board/write")
public String form() {
return "boardWrite";
}
//등록 폼에서 전송된 데이터 처리
board.xml 내용추가
<definition name="boardWrite" extends="main">
<put-attribute name="title" value="게시판 글쓰기"/>
<put-attribute name="css" value="/WEB-INF/views/board/boardCSS.jsp"/>
<put-attribute name="body" value="/WEB-INF/views/board/boardWrite.jsp"/>
</definition>
boardWrite.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!-- 게시판 글쓰기 시작 -->
<div class="page-main">
<h2>글쓰기</h2>
<form:form action="write" id="board_register"
enctype="multipart/form-data"
modelAttribute="boardVO">
<ul>
<li>
<form:label path="category">분류</form:label>
<form:select path="category">
<!-- 이 옵션을 기본 선택으로 지정해둔 코드 -->
<option disabled="disabled" selected>선택하세요</option>
<form:option value="1">자바</form:option>
<form:option value="2">데이터베이스</form:option>
<form:option value="3">자바스크립드</form:option>
<form:option value="4">기타</form:option>
</form:select>
<form:errors path="category" cssClass="error-color"/>
</li>
<li>
<form:label path="title">제목</form:label>
<form:input path="title"/>
<form:errors path="title" cssClass="error-color"/>
</li>
<li>
<form:label path="content">내용</form:label>
<form:textarea path="content"/>
<form:errors path="content" cssClass="error-color"/>
</li>
<li>
<form:label path="upload">파일 업로드</form:label>
<input type="file" name="upload" id="upload">
</li>
</ul>
<div class="align-center">
<form:button class="default-btn">전송</form:button>
<input type="button" value="목록"
class="default-btn"
onclick="location.href='list'">
</div>
</form:form>
</div>
<!-- 게시판 글쓰기 끝 -->

webapp => upload
업로드되는 파일의 위치이다.
FileUtil.java 내용추가
화면 폼이 나왔으니까 이제 내용(파일 등)을 전송하는 법 작성
내용은 upload 폴더로 이동한다.
>> 전송(insert)작업을 하기전에 FileUtil에서 파일 작업을 먼저해야됨.
//업로드 상대 경로
private static final String UPLOAD_PATH = "/upload";
//파일 업로드 처리
public static String createFile(HttpServletRequest request,
MultipartFile file) throws IllegalStateException,IOException{
//컨텍스트 루트상의 절대 경로 구하기
String path = request.getServletContext().getRealPath(UPLOAD_PATH);
String filename = null;
if(file!=null && !file.isEmpty()) {
//파일명이 중복되지 않도록 파일명 변경
//원래 파일명을 보존하지 않을경우
filename = UUID.randomUUID()+
file.getOriginalFilename()
.substring(file.getOriginalFilename()
.lastIndexOf("."));
// _(언더바) 이후에 원래 파일명을 보존할 경우
//filename = UUID.randomUUID()+"_"+file.getOriginalFilename();
}
return filename;
}
//파일 삭제
public static void removeFile(HttpServletRequest request, String filename) {
if(filename !=null) {
//컨텍스트 루트상의 절대 경로 구하기
String path = request.getServletContext().getRealPath(UPLOAD_PATH);
File file = new File(path+"/"+filename);
if(file.exists()) file.delete();
}
}
BoardMapper.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="kr.spring.board.dao.BoardMapper">
<!-- 글쓰기 -->
<insert id="insertBoard" parameterType="boardVO">
INSERT INTO spboard(
board_num,
category,
title,
content,
filename,
ip,
mem_num)
VALUES(
spboard_seq.nextval,
#{category},
#{title},
#{content},
#{filename},
#{ip},
#{mem_num})
</insert>
</mapper>
BoardserviceImpl.java
@Override
public void insertBoard(BoardVO board) {
boardMapper.insertBoard(board);
}
BoardController.java
//등록 폼에서 전송된 데이터 처리
@PostMapping("/board/write")
public String submit(@Valid BoardVO boardVO,
BindingResult result,
HttpServletRequest request,
HttpSession session,
Model model) throws IllegalStateException,IOException {
log.debug("<<게시판 글 저장>> : "+boardVO);
//유효성 체크 결과 오류가 있으면 폼 호출
if(result.hasErrors()) {
return form();
}
//오류가 없으면 정보처리를 함.
//회원번호 세팅
MemberVO vo = (MemberVO)session.getAttribute("user");
boardVO.setMem_num(vo.getMem_num());
//ip셋팅
boardVO.setIp(request.getRemoteAddr());
//파일 업로드
boardVO.setFilename(FileUtil.createFile(request,boardVO.getUpload())); //여길 지나면 업로드가 된거임
//글쓰기
boardService.insertBoard(boardVO);
//View 메시지 처리
model.addAttribute("message","성공적으로 글이 등록되었습니다.");
model.addAttribute("url",request.getContextPath()+"/board/list");
return "common/resultAlert";
}
message=>validation.properties
VO에서 NotBlak 같은 것을 설정 했을 때 나올 값들 설정
#게시판
Size.category=분류를 선택하세요
NotBlank.title=제목은 필수
NotEmpty.content=내용은 필수
application.yml 추가설정
servlet:
multipart:
max-file-size: 50MB #파일 한 개당 최대 사이즈
max-request-size: 200MB #요청당 최대 파일 크기
tomcat:
max-http-form-post-size: 200MB #톰캣에서 허용하는 파일 업로드 사이즈




FileUtil에 설정을 하나 빼먹어서 upload 폴더에 파일이 업로드가 안됨.
//upload 폴더로 업로드한 파일이 이동되도록 하는 코드
file.transferTo(new File(path+"/"+filename));
다시 SQL에 있는 값을 삭제하고 똑같이 업로드하면 upload안에 업로드한 파일이 들어간다.



제목과 내용은 not null이지만 파일 null 허용이다. 그치만 파일을 보내지않으면 에러가난다.
why?
SQL에 null을 허용했다고 해도 mybatis 자체에서 null을 허용하지 않기 때문에 에러가난다.
그러므로 이 에러를 나지않게 설정을 추가로 해줘야된다.
BoardMapper.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="kr.spring.board.dao.BoardMapper">
<!-- 글쓰기 -->
<insert id="insertBoard" parameterType="boardVO">
INSERT INTO spboard(
board_num,
category,
title,
content,
filename,
ip,
mem_num)
VALUES(
spboard_seq.nextval,
#{category},
#{title},
#{content},
#{filename,jdbcType=VARCHAR},
#{ip},
#{mem_num})
</insert>
</mapper>
jdbcType=VARCHAR를 4번째 열인 filename에 적어준 뒤 다시 실행하여 파일을 빼고 보내면 에러없이 전달된다.

카테고리가 유효성처리가 안되는 문제를 해결
BoardVo 수정
@NotBlank
private String category; //카테고리 분야
validation.properties 수정
#게시판
NotBlank.category=분류를 선택하세요
NotBlank.title=제목은 필수
NotEmpty.content=내용은 필수

코드 실행순서
>>SQL 만들기
>>VO 객체지정
>>BoardMapper 인터페이스로 dao지정
>>BoardService 인터페이스로 mapper의 서비스 네트워크 지정
>> BoardServiceImpl 클래스를 생성해서 service의 호출을 돕는다.
>> BoardController 클래스를 생성해서 연결 및 화면구현을 돕는다.
백앤드 쪽이 세팅이 끝났으면 프론트앤드 쪽을 세팅한다.
>>모든 화면에서 다 보이는 tiles의 board.xml을 설정한다.
>>tiles에서 값으로 저장한 jsp들을 만든다.
>>boardcss.jsp를 호출해서 꾸며주는 css 파일을 만든다.
>>css가 끝나면 jsp를 설정해준다
>>Appconfig에서 xml 과 jsp와 연결해주고 추가로 로그인 체크 인터셉터를 설정해준다.
>> header.jsp 에서 링크 설정을 해준다.
[헤더에 있는 board/list 링크를 누르면 controller에 있는 getMapping 링크가 연결되면서 return 값으로 boardList를 보냄.
그러면 board.xml에서 name값으로 boardList를 받고 데피니션 안에 있는 링크값들을 화면에 뿌려줌.
링크값들 역시 jsp파일들이기 때문에 jsp파일 안에 내용들이 화면에 뿌려짐 ]
<layout_basic=>header => controller => xml => jsp>
>>Controller에서 게시판 글쓰기 등록 폼을 만든다.
>> 컨트롤러에서 설정한 return 값을 board.xml에서 데피니션을 만들어준다.
>>xml에서 put-에트리뷰트 한 링크값 jsp를 만든다.
>>만든 jsp의 화면을 만든다.
화면 폼이 나왔으니까 이제 내용(파일 등)을 전송하는 법 작성
내용은 upload 폴더로 이동한다.
>> 전송(insert)작업을 하기전에 FileUtil에서 파일 작업을 먼저해야됨.
>>insert 작업 SQL문의 내용이 길기 때문에 BoardMapper.xml 를 만들어서 BoardMapper.java 대신 사용한다
>>xml에서 작성한 SQL문을 BoardServiceImpl에서 호출을 해준다.
>>BoardServiceImpl에서 전송받은 데이터를 Controller에서 처리한다.(PostMapping)
>>** (미리못한 것들 설정)
VO에서 NotBlak 같은 것을 설정 했을 때 나올 값들 validation.properties 에서 설정
>>application.yml에서 업로드 할 파일 크기 설정 (순서는 상관없고 파일을 사용한다고하면 넣어주면됨)
'쌍용교육(JAVA) > SpringBoot' 카테고리의 다른 글
쌍용교육 -JSP수업 96일차 ch15SpringPage(7) (0) | 2024.07.03 |
---|---|
쌍용교육 -JSP수업 94일차 ch15SpringPage(5) (0) | 2024.07.01 |
쌍용교육 -JSP수업 92일차 ch15SpringPage(3) (1) | 2024.06.27 |
쌍용교육 -JSP수업 91일차 ch15SpringPage(2) (0) | 2024.06.26 |
쌍용교육 -JSP수업 90일차 ch15SpringPage (0) | 2024.06.25 |