AuthorMapper.java
에 구현된 메서드에 대해서는 테스트를 진행하였고 AuthorService.java
의 메서드에 대해서는 작성은 하였지만 테스트를 하지 않았다. 그에 대한 테스트도 진행하려 한다.src/test/java
경로에 com.store.service
패키지를 생성한 뒤 AuthorServiceTests.java
클래스를 생성한다.package com.store.service;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.store.model.AuthorVO;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file/src/main/webapp/WEB-INF/spring/root-context.xml")
public class AuthorServiceTests {
/* AuthorService 의존성 주입 */
@Autowired
private AuthorService service;
@Test
public void authorEnrollTest() throws Exception {
AuthorVO author = new AuthorVO();
author.setNationId("01");
author.setAuthorName("테스트");
author.setAuthorIntro("테스트 소개");
service.authorEnroll(author);
}
}
package com.store.service;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.store.model.AuthorVO;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml") // 수정
public class AuthorServiceTests {
/* AuthorService 의존성 주입 */
@Autowired
private AuthorService service;
@Test
public void authorEnrollTest() throws Exception {
AuthorVO author = new AuthorVO();
author.setNationId("01");
author.setAuthorName("테스트");
author.setAuthorIntro("테스트 소개");
service.authorEnroll(author);
}
}
AuthorService.java
인터페이스를 의존성 주입해주는 코드를 추가한다.@Controller
@RequestMapping("/admin")
public class AdminController {
private static final Logger logger = LoggerFactory.getLogger(AdminController.class);
@Autowired
private AuthorService authorService;
authorEnroll.do
인 POST방식의 url매핑 메서드를 추가한다.BoardVO
타입 변수 RedirectAttributes
타입 변수를 추가하였다.BoardVO
객체는 뷰가 전송하는 작가 관련 데이터를 받기 위해서이다.RedirectAttributes
객체는 해당 메서드가 종료된 뒤 리다이렉트 방식으로 다른 페이지로 전송할 때 성공 메시지를 전송하기 위해서 추가했다.(리다이렉트 방식으로 이동할 때 데이터 전송을 위해 사용되는 Model 객체라고 생각하면 됨)package com.store.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.store.model.AuthorVO;
import com.store.service.AuthorService;
@Controller
@RequestMapping("/admin")
public class AdminController {
private static final Logger logger = LoggerFactory.getLogger(AdminController.class);
@Autowired
private AuthorService authorService;
/* 관리자 메인 페이지 이동 */
@RequestMapping(value = "main", method = RequestMethod.GET)
public void adminMainGET() throws Exception {
logger.info("관리자 페이지 이동");
}
/* 상품 관리 페이지 접속 */
@RequestMapping(value = "goodsManage", method = RequestMethod.GET)
public void goodsManageGET() throws Exception {
logger.info(">>>>>>>>>> 상품 관리 페이지 접속");
}
/* 상품 등록 페이지 접속 */
@RequestMapping(value = "goodsEnroll", method = RequestMethod.GET)
public void goodsEnrollGET() throws Exception {
logger.info(">>>>>>>>>> 상품 등록 페이지 접속");
}
/* 작가 관리 페이지 접속 */
@RequestMapping(value = "authorManage", method = RequestMethod.GET)
public void anthorManageGET() throws Exception {
logger.info(">>>>>>>>>> 작가 관리 페이지 접속");
}
/* 작가 등록 페이지 접속 */
@RequestMapping(value = "authorEnroll", method = RequestMethod.GET)
public void authorEnrollGET() throws Exception {
logger.info(">>>>>>>>>> 작가 등록 페이지 접속");
}
/* 작가등록 */
@RequestMapping(value = "authorEnroll.do", method = RequestMethod.POST)
public String authorEnrollPOST(AuthorVO author, RedirectAttributes rttr) throws Exception {
}
}
/* 작가등록 */
@RequestMapping(value = "authorEnroll.do", method = RequestMethod.POST)
public String authorEnrollPOST(AuthorVO author, RedirectAttributes rttr) throws Exception {
logger.info("authorEnroll : " + author);
}
AuthorService.java
의 authorEnroll
메서드를 호출한다. 뷰로부터 전달받은 등록할 작가 정보가 담긴 BoardVO
변수를 매개변수로 작성한다. /* 작가등록 */
@RequestMapping(value = "authorEnroll.do", method = RequestMethod.POST)
public String authorEnrollPOST(AuthorVO author, RedirectAttributes rttr) throws Exception {
logger.info("authorEnroll : " + author);
authorService.authorEnroll(author); // 작가 등록 쿼리 수행
}
/* 작가등록 */
@RequestMapping(value = "authorEnroll.do", method = RequestMethod.POST)
public String authorEnrollPOST(AuthorVO author, RedirectAttributes rttr) throws Exception {
logger.info("authorEnroll : " + author);
authorService.authorEnroll(author); // 작가 등록 쿼리 수행
return "redirect:/admin/authorManage";
}
addFlashAttribute
메서드를 사용하였다.addFlashAttribute
메서드를 사용하였다. /* 작가등록 */
@RequestMapping(value = "authorEnroll.do", method = RequestMethod.POST)
public String authorEnrollPOST(AuthorVO author, RedirectAttributes rttr) throws Exception {
logger.info("authorEnroll : " + author);
authorService.authorEnroll(author); // 작가 등록 쿼리 수행
rttr.addFlashAttribute("enroll_result", author.getAuthorName()); // 등록 성공 메시지(작가이름)
return "redirect:/admin/authorManage";
}
admin_content_subject
인 <div>
태그 바로 아래에 작가 정보를 작성하고 전송할 수 있는 버튼이 있는 태그 코드들을 추가하였다.<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="../resources/css/admin/authorEnroll.css">
<script
src="https://code.jquery.com/jquery-3.4.1.js"
integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU="
crossorigin="anonymous"></script>
</head>
</head>
<body>
<div class="wrapper">
<div class="wrap">
<!-- gnv_area -->
<div class="top_gnb_area">
<ul class="list">
<li><a href="/main">메인 페이지</a></li>
<li><a href="/member/logout.do">로그아웃</a></li>
<li>고객센터</li>
</ul>
</div>
<!-- top_subject_area -->
<div class="admin_top_wrap">
<span>관리자 페이지</span>
</div>
<!-- contents-area -->
<div class="admin_wrap">
<!-- 네비영역 -->
<div class="admin_navi_wrap">
<ul>
<li >
<a class="admin_list_01" href="/admin/goodsEnroll">상품 등록</a>
</li>
<li>
<a class="admin_list_02" href="/admin/goodsManage">상품 관리</a>
</li>
<lI>
<a class="admin_list_03" href="/admin/authorEnroll">작가 등록</a>
</lI>
<lI>
<a class="admin_list_04" href="/admin/authorManage">작가 관리</a>
</lI>
<lI>
<a class="admin_list_05">회원 관리</a>
</lI>
</ul>
</div>
<div class="admin_content_wrap">
<div class="admin_content_subject"><span>작가 등록</span></div>
<!-- 작가 정보 작성 및 전송 코드 추가 -->
<div class="admin_content_main">
<form action="/admin/authorEnroll.do" method="post" id="enrollForm">
<div class="form_section">
<div class="form_section_title">
<label>작가 이름</label>
</div>
<div class="form_section_content">
<input name="authorName">
</div>
</div>
<div class="form_section">
<div class="form_section_title">
<label>소속 국가</label>
</div>
<div class="form_section_content">
<select name="nationId">
<option value="none" selected>=== 선택 ===</option>
<option value="01">국내</option>
<option value="02">국외</option>
</select>
</div>
</div>
<div class="form_section">
<div class="form_section_title">
<label>작가소개</label>
</div>
<div class="form_section_content">
<input name="authorIntro" type="text">
</div>
</div>
</form>
<div class="btn_section">
<button id="cancelBtn" class="btn">취 소</button>
<button id="enrollBtn" class="btn enroll_btn">등 록</button>
</div>
</div>
<!-- 작가 정보 작성 및 전송 코드 추가 -->
</div>
<div class="clearfix"></div>
</div>
<!-- Footer 영역 -->
<div class="footer_nav">
<div class="footer_nav_container">
<ul>
<li>회사소개</li>
<span class="line">|</span>
<li>이용약관</li>
<span class="line">|</span>
<li>고객센터</li>
<span class="line">|</span>
<li>광고문의</li>
<span class="line">|</span>
<li>채용정보</li>
<span class="line">|</span>
</ul>
</div>
</div> <!-- class="footer_nav" -->
<div class="footer">
<div class="footer_container">
<div class="footer_left">
<img src="../resources/img/Logo.png">
</div>
<div class="footer_right">
(주) 이름없는 회사 대표이사 : OOO
<br>
사업자등록번호 : ooo-oo-ooooo
<br>
대표전화 : oooo-oooo(발신자 부담전화)
<br>
<br>
COPYRIGHT(C) <strong>yoonbitnara.github.io</strong> ALL RIGHTS RESERVED.
</div>
<div class="clearfix"></div>
</div>
</div> <!-- class="footer" -->
</div> <!-- class="wrap" -->
</div> <!-- class="wrapper" -->
</body>
</html>
<form action="/admin/authorEnroll.do" method="post" id="enrollForm">
</form>
<input>, <select>
태그의 name 속성 값이 일치하도록 작성해야 한다. 일치하지 않으면 데이터는 서버로 전송되지 않는다.<input name="authorName">
<select name="nationId">
<input name="authorIntro" type="text">
<input>
을 사용하지 않고 <select>
를 사용하였다. 국내, 국외 두 정보중 한 가지를 선택하도록 강제하기 위해 <select>
를 사용하였다.<select name="nationId">
<option value="none" selected>=== 선택 ===</option>
<option value="01">국내</option>
<option value="02">국외</option>
</select>
<script>
/* 등록버튼 */
$("#enrollBtn").click(function(){
$("#enrollForm").submit();
});
/* 취소버튼 */
$("#cancelBtn").click(function() {
location.href="/admin/authorManage";
});
</script>
enroll_result
)를 전송하였다. 이 데이터를 활용하여 성공을 알리는 경고창을 띄우는 코드를 작성한다.authorManage.jsp
하단에 <script>
태그를 추가 후 페이지가 로드될 때 반드시 실행이 되는 익명 함수를 추가한다.<script>
$(document).ready(function() {
});
</script>
$(document).ready(function() {
let result = "${enroll_result}";
checkResult(result);
function checkResult(result) {
if (result == "") {
return;
}
alert("작가'${enroll_result}' 님을 등록하였습니다.");
}
});
${enroll_result}
는 사용자가 작성한 값이 그대로 전송되기 때문에 XSS 공격과 같이 스크립트 코드를 주입시키는 웹사이트 공격에 취약할 수 있다.${enroll_result}
는 작가 등록 때 작성한 작가 이름인데 사용자가 <script>alert('공격');</script>
을 작가 이름에 작성을 한다면 작가 관리 페이지에 alert문이 실행될 수 있다.<c:out>
을 사용하는 방법이다.<c:out>
는 변수의 내용을 출력할 때 사용되는 태그인데 해당 태그에 HTML문자를 escape하는 기능이 있기 때문이다.${enroll_result}
에 <c:out>
을 적용시키고자 한다. 먼저 JSTL 라이브러리 코드를 추가한다.<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
${enroll_result}
를 <c:out>
태그를 적용 한다. // 변경 전
let result = "${enroll_result}";
// 변경 후
let result = '<c:out value="${enroll_result}"/>';