form 요소


웹 페이지에서는 form 요소를 사용하여 사용자로부터 입력을 받을 수 있다.
또한, 사용자가 입력한 데이터를 서버로 보낼 때에도 form 요소를 사용한다. 


<form action="처리할페이지주소" method="get|post"></form>


action 속성은 입력받은 데이터를 처리할 서버 상의 스크립트 파일의 주소를 명시한다.
이렇게 전달받은 데이터를 처리하는 스크립트 파일을 폼 핸들러(form-handler)라고 한다.

method 속성은 입력받은 데이터를 서버에 전달할 방식을 명시한다.

따라서 사용자가 form 요소를 통해 입력한 데이터는 action 속성에 명시된 위치로 method 속성의 방식을 통해 전달된다.

method 속성
method 속성을 통해 명시할 수 있는 form 요소의 전달 방식은 GET 방식과 POST 방식으로 나눠진다.

 

GET 방식은 주소에 데이터(data)를 추가하여 전달하는 방식이다.
데이터가 주소 입력창에 그대로 나타나며, 전송할 수 있는 데이터의 크기 또한 제한적이다.
따라서 검색 엔진의 쿼리(query)와 같이 크기가 작고 중요도가 낮은 정보를 보낼 때 주로 사용한다.

POST 방식은 데이터(data)를 별도로 첨부하여 전달하는 방식이다.
데이터가 외부에 드러나지 않으며, 전송할 수 있는 데이터의 크기 또한 제한이 없다.
따라서 보안성 및 활용성이 GET 방식보다 좋다.


reasonly 속성 vs disable 속성

 

readonly 속성은 사용자가 입력 필드를 볼 수는 있으나, 수정할 수는 없도록 설정합니다.
disabled 속성과 다른 점은 전송 버튼(submit)을 누르면 초깃값이 서버로 전송된다는 점입니다.


disabled 속성은 사용자가 입력 필드를 아예 사용할 수 없도록 설정합니다.
disabled 속성이 설정된 입력 필드는 사용할 수도 없고, 클릭할 수도 없습니다.( 서버로 전송 안됨) 

학과 : <br><input type="text" name="department" value="컴퓨터공학과" readonly><br>
학과 : <br><input type="text" name="department" value="컴퓨터공학과" disabled><br>


HTML5 

 

HTML5는 웹 상에서 콘텐츠(content)를 구성하고 보여주기 위한 HTML 언어의 최신 표준 권고안입니다.
HTML5는 HTML 4.01, XHTML 1.1 등을 대체하는 HTML의 차세대 표준입니다.
HTML5는 XML이나 XHTML과는 달리 문법적으로 매우 유연하게 대처합니다.

 


form 속성


form 속성은 해당 input 요소의 위치에 상관없이 포함될 form 요소를 명시해 줍니다.

포함할 form 요소의 id 속성값을 공백으로 연결하여, 둘 이상의 form 요소에 포함할 수도 있습니다.

<form action="/examples/media/request.php" id="user">
    사용자 : <input type="text" name="username"><br><br>
</form>

...

비밀번호 : <input type="password" name="password" form="user">



 

 

'HTML,CSS' 카테고리의 다른 글

HTML5 span 과 div의 차이  (0) 2021.02.05
CSS 반드시 기억해야 하는 선택자 30개  (0) 2021.01.17
CSS div 왼쪽, 오른쪽으로 붙이기  (0) 2020.12.09
button  (0) 2020.11.13
CSS 공부  (0) 2020.10.26

2hyes.tistory.com/91

 

github: 깃헙에 프로젝트 올리는 법(윈도우)

github에 가입이 되어있는 상태라는 가정 하에 방법을 작성하겠다. 사실 내가 자꾸 명령어를 까먹어서 쓰는 거다..🤦🏻‍♀️ 1. Git(깃)을 설치( https://git-scm.com/downloads ) OS에 맞는 것으로 설치해��

2hyes.tistory.com

 

'기타' 카테고리의 다른 글

포트 충돌 날 때 윈도우 Port 확인/제거  (0) 2021.02.05
디버깅하는법  (0) 2020.09.24
front-end, back-end 가 공부해야할 길(?)  (0) 2020.08.03

Ajax는 JavaScript의 라이브러리중 하나이며 Asynchronous Javascript And Xml(비동기식 자바스크립트와 xml)의 약자

브라우저가 가지고있는 XMLHttpRequest 객체를 이용해서 전체 페이지를 새로 고치지 않고도 페이지의 일부만을 위한 데이터를 로드하는 기법 이며 
Ajax를 한마디로 정의하자면 JavaScript를 사용한 비동기 통신, 클라이언트와 서버간에 XML 데이터를 주고받는 기술이라고 할 수 있겠습니다.

 

AJAX just uses a combination of:
A browser built-in XMLHttpRequest object (to request data from a web server)
JavaScript and HTML DOM (to display or use the data)

 

What, exactly, is the DOM? 

wit.nts-corp.com/2019/02/14/5522

 

(번역) DOM은 정확히 무엇일까?

본 번역문은 원작자의 동의하에 번역 및 게시되었습니다. 최근 잘못 이해하고 있었던 DOM에 대해 정확한 개념을 정리해 보고자 Ire Aderinokun이 작성한 What, exactly, is the DOM? 문서를 번역해 보았습�

wit.nts-corp.com

 

 

----------------------------------------------------------------------------------------------------------------------------------

※ 비동기(async)방식이란?

비동기 방식은 웹페이지를 리로드하지 않고 데이터를 불러오는 방식입니다. 
이 방식의 장점은 페이지 리로드의 경우 전체 리소스를 다시 불러와야하는데 
이미지, 스크립트 , 기타 코드등을 모두 재요청할 경우 불필요한 리소스 낭비가 발생하게 되지만 
비동기식 방식을 이용할 경우 필요한 부분만 불러와 사용할 수 있으므로 매우 큰 장점이 있습니다.
--------------------------------------------------------------------------------------------------------------------------- 

왜 사용하는가? 

기본적으로 HTTP프로토콜은 클라이언트쪽에서 Request를 보내고 Server쪽에서 Response를 받으면 이어졌던 연결이 끊기게 되어있습니다. 
그래서 화면의 내용을 갱신하기 위해서는 다시 request를 하고 response를 하면서 페이지 전체를 갱신하게 됩니다. 
하지만 이렇게 할 경우 페이지의 일부분만 갱신할 경우에도 페이지 전체를 다시 로드해야하는데 엄청난 자원낭비와 시간낭비를 초래하고 말것입니다. 
하지만 ajax는 html 페이지 전체가아닌 일부분만 갱신할수 있도록 XML HttpRequest객체를 통해 서버에 request를 합니다. 
이 경우 Json이나 xml형태로 필요한 데이터만 받아 갱신하기 때문에 그만큼의 자원과 시간을 아낄 수 있습니다. 
요새 웹페이지에서 가장 중요한것은 속도가 아닐까싶습니다. 이 이유하나만으로도 Ajax를 사용해야 하는 이유로써 충분합니다.

-----------------------------------------------------------------------------------------------------------------------------------

Ajax의 장점

1. 웹페이지의 속도향상
2. 서버의 처리가 완료 될때까지 기다리지 않고 처리 가능하다.
3. 서버에서 Data만 전송해면 되므로 전체적인 코딩의 양이 줄어든다.
4. 기존 웹에서는 불가능했던 다양한 UI를 가능하게 해준다. 사진공유 사이트 Flickr의 경우 사진의 제목이나 태그를 페이지 리로드 없이 수정할 수 있다.

Ajax 의 단점
1. 히스토리 관리가 안 된다. (보안에 좀 더 신경을 써야한다.)
2. 연속으로 데이터를 요청하면 서버 부하가 증가할 수 있다.
3. XMLHttpRequest를 통해 통신을 하는 경우사용자에게 아무런 진행 정보가 주어지지 않는다. 그래서 아직 요청이 완료되지 않았는데 사용자가 페이지를 떠나거나 오작동할 우려가 발생하게 된다. 

-----------------------------------------------------------------------------------------------------------------------------------
▶Jquery와의 시너지  

Ajax하면 Jquery에 대한 설명을 빼놓을 수 없습니다. 
일반 Javascript만으로 Ajax를 하게되면 코딩량도 많아지고 브라우저별로 구현방법이 다른 단점이 있는데 jquery를 이용하면 더 적은 코딩량과 동일한 코딩방법으로 대부분의 브라우저에서 같은 동작을 할 수 있게 됩니다.
 jquery ajax를 사용하면, HTTP Get방식과 HTTP Post방식 모두를 사용하여 원격 서버로부터 데이터를 요청할 수 있습니다.
 Jquery는 Ajax처럼 JavaScript의 라이브러리 중 하나인데 자바스크립트를 좀 더 사용하기 쉽게 패키징화 시켜놓은 것입니다. 

 

coding-factory.tistory.com/143

 

[Ajax] Ajax란 무엇인가?

▶ Ajax란? Ajax는 JavaScript의 라이브러리중 하나이며 Asynchronous Javascript And Xml(비동기식 자바스크립트와 xml)의 약자입니다. 브라우저가 가지고있는 XMLHttpRequest 객체를 이용해서 전체 페이지를..

coding-factory.tistory.com

 

TestController

package egovframework.example.test.web;

import java.io.File;
import java.util.HashMap;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import egovframework.example.test.domain.Search;
import egovframework.example.test.domain.TestVO;
import egovframework.example.test.service.TestService;

@Controller
public class TestController {

	@Autowired
	private TestService testServiceImpl;

	@RequestMapping(value = "/testList.do")
	public String testListView() {
		return "test/testList";
	}
	@RequestMapping(value = "/getTestList.do", produces = "application/json")
	@ResponseBody
	public ResponseEntity<HashMap<String, Object>> testListDo(Search search) throws Exception {

		HashMap<String, Object> result = new HashMap<>();

		// 전체 게시글 개수를 얻어와 listCnt에 저장
		int listCnt = testServiceImpl.getBoardListCnt(search);

		// 검색
		search.pageInfo(listCnt);

		// 페이징
		result.put("pagination", search);

		// 게시글 화면 출력
		result.put("list", testServiceImpl.selectTest(search));
		return ResponseEntity.ok(result);
	}

	// 글 작성 버튼 구현
	@RequestMapping(value = "/insertTest.do", produces = "application/json")
	@ResponseBody
	public ResponseEntity<TestVO> write(TestVO testVO) throws Exception {
		String fileName = null;
		MultipartFile uploadFile = testVO.getUploadFile();
		if (uploadFile != null && !uploadFile.isEmpty()) {
			String originalFileName = uploadFile.getOriginalFilename();
			String ext = FilenameUtils.getExtension(originalFileName); // 확장자 구하기
			UUID uuid = UUID.randomUUID(); // UUID 구하기
			fileName = uuid + "." + ext;
			uploadFile.transferTo(new File("C:\\upload\\" + fileName));
		}
		testVO.setFileName(fileName);

		int testId = testServiceImpl.insertTest(testVO);
		testVO.setTestId(testId);
		testVO = testServiceImpl.selectDetail(testVO);
		return ResponseEntity.ok(testVO);
	}

	// 글 작성 클릭시 글 작성 페이지로 이동
	@RequestMapping(value = "/testRegister.do")
	public String testRegister() {
		return "test/testRegister";
	}

	// 제목 클릭 시 상세보기
	@RequestMapping(value = "/testDetail.do")
	public String viewForm(@ModelAttribute("testVO") TestVO testVO, Model model, HttpServletRequest request)
			throws Exception {

		int testId = Integer.parseInt(request.getParameter("testId"));
		testVO.setTestId(testId);

		TestVO resultVO = testServiceImpl.selectDetail(testVO);
		model.addAttribute("result", resultVO);

		return "test/testDetail";
	}

	// 수정하기
	@RequestMapping(value = "/updateTest.do", produces = "application/json")
	@ResponseBody
	public ResponseEntity<TestVO> updateTest(TestVO testVO) throws Exception {
		// 파일 업로드 처리
		String fileName = null;
		MultipartFile uploadFile = testVO.getUploadFile();
		if (uploadFile != null && !uploadFile.isEmpty()) {
			String originalFileName = uploadFile.getOriginalFilename();
			String ext = FilenameUtils.getExtension(originalFileName); // 확장자 구하기
			UUID uuid = UUID.randomUUID(); // UUID 구하기
			fileName = uuid + "." + ext;
			uploadFile.transferTo(new File("C:\\upload\\" + fileName));
		}
		testVO.setFileName(fileName);
		System.out.println(testVO);
		testServiceImpl.updateTest(testVO);
		testVO = testServiceImpl.selectDetail(testVO);
		return ResponseEntity.ok(testVO);
	}

	// 삭제하기
	@RequestMapping(value = "/deleteTest.do", produces = "application/json")
	@ResponseBody
	public ResponseEntity<TestVO> deleteTest(TestVO testVO) throws Exception {
		testVO = testServiceImpl.selectDetail(testVO);
		testServiceImpl.deleteTest(testVO);
		return ResponseEntity.ok(testVO);
	}
}

testRegister

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<!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">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet"
	href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script
	src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script
	src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script
	src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</head>
<body>
	<div class="container">
		<table class="table table-bordered">
			<thead>
				<h1>글쓰기</h1>
			</thead>
			<tbody>
				<!-- enctype="multipart/form-data" 이 부분을 사용해 줘야지만 파일을 전송할 수 있다. -->
				<form id="form_test" action="insertTest.do" method="post"
					encType="multipart/form-data">
					<tr>
						<th>제목:</th>
						<td><input type="text" placeholder="제목을 입력하세요. "
							name="testTitle" id="testTitle" class="form-control" /></td>
					</tr>
					<tr>
						<th>내용:</th>
						<td><textarea placeholder="내용을 입력하세요 . " id="testContent"
								name="testContent" class="form-control" style="height: 200px;"></textarea></td>
					</tr>
					<tr>
						<th>첨부파일:</th>
						<td><input type="file" id="uploadFile" name="uploadFile"></td>
					</tr>
					<tr>
						<td colspan="2">
							<button id="btn_register" type="button" class="btn btn_register">등록</button>
							<button id="btn_previous" type="button" class="btn btn_previous">이전</button>
					</tr>
				</form>
			</tbody>
		</table>
	</div>

</body>
<script type="text/javascript">
	//글쓰기
	$(document).on('click', '#btn_register', function(e) {

		//데이터를 담아내는 부분 상수 const로
		//jquery val() : Form Element 의 값을 받아오는데 쓰인다. (주로 input 이나 textarea 정도?)- 주의해야할 점은 Form Element 이외의 값은 받아오질 못한다는 점.
		//문자열 좌우에서 공백을 제거하는 함수가 trim() 함수 입니다.
		const testTitle = $("#testTitle").val().trim();
		const testContent = $("#testContent").val().trim();
		const uploadFile = $("#uploadFile")[0].files[0];

		//'==' 연산자를 이용하여 서로 다른 유형의 두 변수의 [값] 비교
		//'==='는 엄격한 비교를 하는 것으로 알려져 있다 ([값 & 자료형] -> true). 변수를 비교하거나 어떤 비교를 위해 항상 '===' 연산자를 사용 할 것을 권장한다.
		if (testTitle === '') {
			alert('제목을 입력해주세요.');
			return;
		}

		if (testContent === '') {
			alert('내용을 입력해주세요.');
			return;
		}

		//ajax 통신을 사용해 서버에 데이터를 전송하기 위해 
		//폼데이터 객체를 생성함
		//jquery의 append를 통해서 프로퍼티에 바인딩이 가능하도록 세팅한다..append()선택된 요소의 마지막에 새로운 요소나 콘텐츠를 추가한다.
		var formData = new FormData();
		formData.append("testTitle", testTitle);
		formData.append("testContent", testContent);

		//만약 uploadFile이 undifined거나 null일 경우 폼데이터에 보내지 않도록 한다.
		//이부분 체크하지 않을 경우 undifined가 데이터로 보내지기 때문에 서버에서 에러가 발생한다.
		if (uploadFile)
			formData.append("uploadFile", uploadFile);

		//ajax로 파일전송 폼데이터를 보내기위해
		//enctype, processData, contentType 이 세가지를 반드시 세팅해야한다.
		$.ajax({
			enctype : 'multipart/form-data',
			processData : false,
			contentType : false,
			cache : false,
			url : "./insertTest.do",
			data : formData,
			type : "POST",
			success : function(res) {
				alert('게시글 등록 완료');
				location.href = "./testList.do";
			}
		});
	});

	//이전 클릭 시 testList로 이동
	$("#btn_previous").click(function javascript_onclikc() {
		$(location).attr('href', 'testList.do');
	});
</script>
</html>



testDetail

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!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">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet"
	href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
	integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
	crossorigin="anonymous">

<!-- Optional theme -->
<link rel="stylesheet"
	href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css"
	integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp"
	crossorigin="anonymous">

<!-- Latest compiled and minified JavaScript -->
<script
	src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
	integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
	crossorigin="anonymous"></script>
<link href="/css/test/test.css" rel="stylesheet" type="text/css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
</head>
<body>
	<div class="container">
		<table class="table table-bordered">
			<thead>
				<h1>글 상세보기 Detail</h1>
			</thead>
			<tbody>
				<form action="updateTest.do" id="viewForm" method="post"
					encType="multipart/form-data">
					<tr>
						<th>글번호:</th>
						<td><input name="testId" id="testId" type="text" value="${result.testId}"
							class="form-control" readonly /></td>

					</tr>
					<tr>
						<th>제목:</th>
						<td><input type="text" value="${result.testTitle}"
							id="testTitle" class="form-control" /></td>
					</tr>
					<tr>
						<th>내용:</th>
						<td><textarea id="testContent" class="form-control"
								style="height: 200px;">${result.testContent}</textarea></td>

					</tr>
					<tr>
						<c:if test="${result.fileName ne null}">
							<tr>
								<td>다운로드</td>

								<td><a href="fileDownload.do?fileName=${result.fileName}">
										<input type="text" id="asd" value="${result.fileName}"
										name="fileName" class="form-control" readonly />
								</a>
									<button id="asdasd" type="button" class="btn_previous">파일지우기</button>
							</tr>
						</c:if>
					</tr>


					<tr>
						<th>첨부파일:</th>
						<td><input type="file" id="uploadFile"></td>
					</tr>
					<tr>

						<td colspan="2">
							<button id="btn_previous" type="button" class="btn_previous">이전</button>
							<button id="btn_delete" type="button" class="btn_previous">삭제</button>
							<button id="btn_modify" type="button" class="btn_register">수정</button>
					</tr>
				</form>
			</tbody>
		</table>
	</div>


</body>
<script type="text/javascript">
	const testId = $("#testId").val();

	$(document).on('click', '#btn_modify', function(e) {
		if (confirm("정말 수정하시겠습니까 ?") == true) {
			
			//데이터를 담아내는 부분
			const testTitle = $("#testTitle").val().trim();
			const testContent = $("#testContent").val().trim();
			const uploadFile = $("#uploadFile")[0].files[0];

			if(testTitle === ''){
				alert('제목을 입력해주세요.');
				return;
			}
			
			if(testContent === ''){
				alert('내용을 입력해주세요.');
				return;
			}

			//ajax 통신을 사용해 서버에 데이터를 전송하기 위해 
			//폼데이터 객체를 생성함
			//append를 통해서 프로퍼티에 바인딩이 가능하도록 세팅한다.
			var formData = new FormData();
			formData.append("testId",testId);
			formData.append("testTitle",testTitle);
			formData.append("testContent",testContent);

			//만약 uploadFile이 undifined거나 null일 경우 폼데이터에 보내지 않도록 한다.
			//이부분 체크하지 않을 경우 undifined가 데이터로 보내지기 때문에 서버에서 에러가 발생한다.
			if(uploadFile)
				formData.append("uploadFile",uploadFile);
			
			//ajax로 파일전송 폼데이터를 보내기위해
			//enctype, processData, contentType 이 세가지를 반드시 세팅해야한다.
			$.ajax({
				enctype: 'multipart/form-data',
				processData: false,
				contentType: false,
				cache: false,
				url : "./updateTest.do",
				data : formData,
				type : "POST",
				success : function(res){
					alert('수정 완료');
					location.href='./testList.do';
				}
			})			
		} 
	});
	
	$(document).on('click', '#btn_delete', function(e) {
		if (confirm("정말 삭제하시겠습니까 ?")) {
			$.ajax({
				url : "./deleteTest.do",
				type : "POST",
				data : {
					testId : testId
				},
				success : function(res){
					alert('삭제 완료');
					location.href='./testList.do';
				}
			})
		}
	});
	
	//이전 클릭 시 testList로 이동
	$("#btn_previous").click(function javascript_onclikc() {

		$(location).attr('href', 'testList.do');

	});
	$("#asdasd").click(function javascript_onclikc() {
		$('#asd').val(null);

	});
</script>
</html>

 

 

 

github.com/jodongyeon/boardTestMiso

 

jodongyeon/boardTestMiso

게시판 formsubmit방식과AJAX비동기방식. Contribute to jodongyeon/boardTestMiso development by creating an account on GitHub.

github.com

게시판연습 깃허브주소

1.  Window  -  showView의 Problems를 통해 에러를 확인한다.

 

2. Java Build Path의 Libraries를 확인하여 메이븐, 톰캣, jdk버전을 확인한다.

 

2.5 Properties의 Project Facets에 java Version과 우측의 Runtime을 확인하여 톰켓버전을 맞춘다.

 

3. Project clean , Maven Update 하기 

 

<나는 톰캣버전이 달라서 x 표시가 뜨고 있었다.>

pom.xml

		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-core</artifactId>
			<version>2.7.3</version>
		</dependency>

		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.7.3</version>
		</dependency>

pom.xml에 dependency추가

 

JSON 값을 RESPONSE 해주기 jackson 라이브러리 사용을 위한 설정. 
Jackson은 JSON 데이터 구조를 처리해주는 라이브러리. 
Spring 3.0 이후로부터, Jacskon과 관련된 API를 제공함으로써, Jackson라이브러리를 사용할 때, 자동화 처리가 가능하게 되었다.
덕분에, JSON데이터를 직접 만들던가, GSON or SimpleJSON방식과 같이 직접 키와 벨류를 세팅하는 방식에서 한 단계 더 발전한 방식. 
Spring3.0 이후로 컨트롤러의 리턴 방식이 @RequestBody 형식이라면, Spring은 MessageConverter API를 통해, 컨트롤러가 리턴하는 객체를 후킹 할 수 있다.
Jackson은 JSON데이터를 출력하기 위한  MappingJacksonHttpMessageConverter를 제공. 
만약 우리가 스프링 MessageConverter를 위의 MappingJacksonHttpMessageConverter으로 등록한다면,
컨트롤러가 리턴하는 객체를 다시 뜯어(자바 리플렉션 사용), Jackson의 ObjectMapper API로 JSON 객체를 만들고 난 후, 출력하여 JSON 데이터를 완성합니다.
더욱 편리해진 점은, Spring 3.1 이후로 만약 클래스패스에 Jackson 라이브러리가 존재한다면, ( 쉽게 말해 Jackson을 설치했느냐 안 했느냐 ) 
자동적으로 MessageConverter가 등록된다는 점입니다. 덕분에 우리는 아래와 같이 매우 편리하게 사용할 수 있다.

 

 


dispatcher-servlet.xml

	<mvc:annotation-driven>
		<mvc:message-converters>
			<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
		</mvc:message-converters>
	</mvc:annotation-driven>

 Spring 과 json연동.

 


TestController

@RequestMapping(value = "/testList.do")
	public String testListView() {
		return "test/testList";
	}
	
	@RequestMapping(value = "/getTestList.do", produces = "application/json")
	@ResponseBody
	public ResponseEntity<HashMap<String, Object>> testListDo(Search search) throws Exception {

		HashMap<String, Object> result = new HashMap<>();

		// 전체 게시글 개수를 얻어와 listCnt에 저장
		int listCnt = testServiceImpl.getBoardListCnt(search);

		// 검색
		search.pageInfo(listCnt);

		// 페이징
		result.put("pagination", search);

		// 게시글 화면 출력
		result.put("list", testServiceImpl.selectTest(search));

		return ResponseEntity.ok(result);
	}

 

이전의 modelandview방식의 view를 return 해주는 컨트롤러를 위처럼 비동기 방식의 컨트롤러로 코드를 수정한다.

 

// ajax url을 getTestList.do로 받기 (후킹??)

// produces = "application/json json형태로 response request요청에 따른 response의 content-type을 변경
// @ResponseBody는 서버에서 클라이언트로 응답데이터를 전송하기 위해 사용

 

Spring Framwork에서 제공하는 클래스중 HttpEntity라는 클래스.

이것은 HTTP 요청(Request) 또는 응답(Response)에 해당하는 HttpHeader와 HttpBody를 포함하는 클래스.

이 HttpEntity 라는 클래스를 상속받아 구현한 클래스가 RequestEntity, ResponseEntity ResponseEntity는 당연히 사용자의 HttpRequest에 대한 응답 데이터를 포함하는 클래스. 따라서 HttpStatus, HttpHeaders, HttpBody를 포함.

 

HashMap은 Map을 구현한다. Key와 value를 묶어 하나의 entry로 저장한다는 특징을 갖는다. 그리고 hashing을
사용하기 때문에 많은양의 데이터를 검색하는데 뛰어난 성능을 보인다. Map 인터페이스의 한 종류로 ( "Key", value)로 이뤄져 있다. key 값을 중복이 불가능하고 value는 중복이 가능. value에 null값도 사용 가능하다. 멀티스레드에서 동시에
HashMap을 건드려 Key - value값을 사용하면 문제가 될 수 있다. 멀티쓰레드에서는 HashTable을 쓴다

 

ResponseEntity의 static 메소드인 ok()는 HttpStatus코드의 OK(200)를 응답 데이터에 포함하도록 하고
ResponseEntity의 BodyBuilder를 return함


 TestServiceImpl

@Override
	public List<TestVO> selectTest(Search search) throws Exception {
		search.setPage(search.getPage() * search.getListSize());
		List<TestVO> result = testDAOService.selectTest(search);
		search.setPage(search.getPage() / search.getListSize());
		return result;
	}

페이지 번호에 따라 10개씩 정상적으로 넘어가기 위한 코드

 


testList.jsp

<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<html>

<head>
<!-- Bootstrap CSS -->

<link rel="stylesheet"
	href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css"
	integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS"
	crossorigin="anonymous">

<link href="/css/test/test.css" rel="stylesheet" type="text/css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>

</head>

<body>
	<div class="container">
		<h1>게시판List</h1>
		<div class="testlist">
			<form id="boardForm" name="boardForm" method="post">
				<table class="table table-hover">
					<colgroup>
						<col width="20%" />
						<col width="50%" />
						<col width="15%" />
						<col width="15%" />
					</colgroup>
					<thead>
						<tr>
							<th>번호</th>
							<th>제목</th>
							<th>작성자</th>
							<th>등록일자</th>
						</tr>
					</thead>
					<tbody id="dataSection"></tbody>
				</table>
			</form>
		</div>


		<div>
			<button id="btn_write" type="button">글작성</button>
		</div>

		<br>


		<!-- pagination{s} -->
		<div class="pagination1">
			<ul id="paginationBox" class="pagination">

			</ul>
		</div>
		<!-- pagination{e} -->

		<!-- search{s} -->

		<div class="form-group row justify-content-center">

			<div class="w100" style="padding-right: 10px">
				<select class="form-control form-control-sm" id="keywordType">
					<option value="testTitle">제목</option>
					<option value="testContent">본문</option>
					<option value="testName">작성자</option>
				</select>
			</div>

			<div class="w300" style="padding-right: 10px">
				<input type="text" class="form-control form-control-sm"
					name="keyword" id="keyword">
			</div>

			<div>
				<button class="btn btn-sm btn-primary" name="btnSearch"
					id="btnSearch">검색</button>
			</div>
		</div>
		<!-- search{e} -->

		<!-- 페이지 목록 갯수   -->
		<div class="form-group row justify-content-center">
			<p>게시판 목록 갯수</p>
			<div class="w100" style="padding-right: 10px">
				<select id="listSize" class="form-control form-control-sm">
					<option value="10">10 개</option>
					<option value="15">15 개</option>
					<option value="20">20 개</option>
				</select>
			</div>
		</div>

	</div>
	<input type="hidden" id="searchInput" value="" />
	<input type="hidden" id="searchType" value="testTitle" />
</body>


<script type="text/javascript">
	$(document).ready(function() {
		getPage();
	})

	$("#listSize").change(function() {
		getPage();
	});

	//	글조회
	//	어떤 게시물을 클릭했는지 게시물의 번호(testId)를 넘겨 줘야 함 따라서 게시물 클릭 이벤트에서 게시물의 번호를 인자 값으로 받습니다.
	//  get 방식으로 데이터를 전송합니다. 따라서 ? 연산자를 사용해 testId를 주소 뒤에 붙여 줍니다
	function showDetail(testId) {

		var form = document.getElementById("boardForm");
		var url = "<c:url value='/testDetail.do'/>";
		url = url + "?testId=" + testId;

		form.action = url;
		form.submit();
	}

	//글 작성 버튼 클릭 시 testRegister로 이동
	$("#btn_write").click(function javascript_onclikc() {
		$(location).attr('href', 'testRegister.do');
	});

	$("#btnSearch").click(function() {
		const search = $("#keyword").val();
		const searchType = $("#keywordType").val();

		$("#searchInput").val(search);
		$("#searchType").val(searchType);
		getPage();
	});

	function getPage(page) {
		var listSize = $("#listSize").val();
		var searchType = $("#searchType").val();
		var search = $("#searchInput").val();
		$
				.ajax({
					url : "getTestList.do", //서비스 주소 
					data : { //서비스 처리에 필요한 인자값
						page : page,
						searchType : searchType,
						keyword : search,
						listSize : listSize
					},
					success : function(res) {
						const list = res['list'];
						const pagination = res['pagination'];
						var data = "";
						var block = "";

						console.log(pagination);
						// 테이블의 row를 삽입하는 부분
						for (var i = 0; i < list.length; i++) {
							data += "<tr style='cursor:pointer' onclick='showDetail("
									+ list[i]['testId'] + ")'>";
							data += "<td>" + list[i]['testId'] + "</td>";
							data += "<td>" + list[i]['testTitle'] + "</td>";
							data += "<td>" + list[i]['testName'] + "</td>";
							data += "<td>" + list[i]['testDate'] + "</td>";
							data += "</tr>";
						}

						// 이전버튼 활성화 여부를 결정하는 부분
						if (pagination['prev']) {
							block += "<li class='page-item'><a class='page-link' href='javascript:getPage("
									+ (pagination['startPage'] - 1)
									+ ")'> < </a></li>";
						} else {
							block += "<li class='page-item disabled'><a class='page-link'> < </a></li>";
						}

						// 번호를 표시하는 부분
						for (var i = pagination['startPage']; i < pagination['endPage']; i++) {
							if (page !== i) {
								block += "<li class='page-item'><a class='page-link' href='javascript:getPage("
										+ i + ")'>" + (i + 1) + "</a></li>";
							} else {
								block += "<li class='page-item disabled'><a class='page-link'>"
										+ (i + 1) + "</a></li>";
							}
						}

						if (pagination['next']) {
							block += "<li class='page-item'><a class='page-link' href='javascript:getPage("
									+ (pagination['endPage'])
									+ ")'>  > </a></li>";
						} else {
							block += "<li class='page-item disabled'><a class='page-link'> > </a></li>";
						}
						$("#dataSection").html(data);
						$("#paginationBox").html(block);
					}
				})
	}
</script>

</html>

 


Console

2020-10-19 14:46:55,266 DEBUG [org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor] Written [{pagination=egovframework.example.test.domain.Search@2e77becd, list=[TestVO [testId=264, testTitle=asdf, testContent=asdf, testDate=2020-10-19], TestVO [testId=263, testTitle=fd, testContent=fd, testDate=2020-10-19], TestVO [testId=262, testTitle=fdas, testContent=asdf, testDate=2020-10-19], TestVO [testId=261, testTitle=d d , testContent=df, testDate=2020-10-19], TestVO [testId=260, testTitle= , testContent=asdfasdf, testDate=2020-10-19], TestVO [testId=259, testTitle=d d, testContent=d, testDate=2020-10-19], TestVO [testId=258, testTitle=sdfg, testContent=sdfg, testDate=2020-10-19], TestVO [testId=257, testTitle=sdfg, testContent=sdfg, testDate=2020-10-19], TestVO [testId=256, testTitle=sdfg, testContent=sdfg, testDate=2020-10-19], TestVO [testId=255, testTitle=asdf, testContent=asdf, testDate=2020-10-19]]}] as "application/json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@3e01cad7]
2020-10-19 14:46:55,266 DEBUG [org.springframework.web.servlet.DispatcherServlet] Null ModelAndView returned to DispatcherServlet with name 'action': assuming HandlerAdapter completed request handling
2020-10-19 14:46:55,266 DEBUG [org.springframework.web.servlet.DispatcherServlet] Successfully completed request

콘솔창에 제이슨 형태로 Convert가 된 것을 볼 수 있다.

 

AngularJS란?

AngularJS는 구글에서 만든 자바스크립트 프레임워크로, 2009년에 발표되었고
AngularJS는 자바스크립트로 만든 client 측 MVC/MVVM 프레임워크로 모던 단일 페이지 웹 애플리케이션 개발의 정수이다.
자바스크립트 프레임워크 javascript framework

 

AngularJS 특징

자바스크립트로 작성할 코드량을 줄여준다. 
- Dom을 선택하고 조작하는 자바스크립트 코드를 작성하지 않아도 된다.
양방향 데이터 바인딩이 가능합니다.
- 모델의 데이터와 뷰 데이터가 양방향 데이터 바인딩이 되어, 모델이 바뀌면 뷰 데이터도 같이 변경된다.
HTML, CSS, 로직 등의 개발 영역을 명확하게 분리해준다.
- 기존 자바스크립트에서는 Dom 조작과 이벤트 처리를 위해 HTML을 잘 알고 있어야 했으나, AngularJS는 뷰 코드와 로직 코드가 명확히 분리된다.

 

 

AngularJS 주요개념

Model(모델)
- 단순 자바스크립트 객체로 된 데이터
- 보통 JSON으로 표현되는 애플리케이션의 특정한 데이터 구조를 말합니다.
- json 데이터를 jQuery의 $.ajax 메서드를 래핑한 Angular의 $http를 통해 XHR(XMLHttp Request)로 서버에서 가져오거나 페이지를 로딩할 때 코드에서 직접 (데이터베이스에서) 읽어오도록 할 수 있다.
 그리고 모델을 변경한 다음 다시 반영할 수도 있습니다.
View(뷰)
- 템플릿과 모델이 합쳐져서 보여지는 화면 (Dom구조로 되어있다.)
- MVC 프레임워크를 사용한다면 뷰를 갱신할 모델 데이터를 내려받은 뒤 HTML에서 해당 데이터를 보여줄 것이다.
Controller(컨트롤러)
- 자바스크립트로 된 로직 영역
- 컨트롤러는 서버에서 직접 뷰로 접근하는 일종의 중간 통로로서 필요할 때마다 서버와 클라이언트 통신으로 데이터를 변경한다.
Scope(스코프)$scope
- 뷰와 컨트롤러 사이에서 데이터를 연결해주는 역할                             뷰------>(스코프)----->컨트롤러
- 모델과 뷰를 감시하고, 컨트롤러에 이벤트를 보내는 역할

$ scope 개체로 컨트롤러를 호출
컨트롤러를 만들 때 $scope객체를 인수로 전달합니다.
scope는 controller를 적용한 태그 내에서 사용할 변수나 함수를 저장해 놓을 수 있는 객체입니다.
컨트롤러와 템플릿을 연결하고 기본적으로 컨트롤러와 템플릿을 연결하고 모델을 보광해서 양방향 바인딩을 할 수 있게 하는 객체다.
. $scope는 DOM의 현재 요소/영역을 참조하며(this 와는 다르다), 요소 안의 데이터와 로직을 주시하는 관찰 기능을 가지고 있다. 

Directive(디렉티브)
- html을 확장하는 AngularJS의 지시어
- ex) ng-app, ng-controller, ng-click 등..
Data Binding(데이터 바인딩)
- 모델과 뷰의 데이터를 실시간으로 연동
Module(모듈)
- 모든 자바스크립트 기능들이 ng-app="모듈명"을 시작으로 모듈 단위로 관리된다.
- 컨트롤러, 서비스, 필터 등을 포함하며, 응용프로그램의 서로 다른 기능을 구성하는 컨테이너이다.
Service(서비스)
- 특정 기능을 담당하는 객체
- 싱글톤 객체로 인스턴스가 하나만 존재합니다.

<h1>{{hex}}</h1>

<script>
var app = angular.module('myApp', []);

app.service('hexafy', function() {
    this.myFunc = function (x) {
        return x.toString(16);
    }
});
app.controller('myCtrl', function($scope, hexafy) {
  $scope.hex = hexafy.myFunc(255);
});
</script>

 

 

module

어플리케이션을 정의한다

<div ng-app="myApp" ng-controller="myCtrl">
{{ firstName + " " + lastName }}
</div>
<script>
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
  $scope.firstName = "John";
  $scope.lastName = "Doe";
});
</script>



var app = angular.module("myApp", []);
모듈 정의의 [] 매개 변수를 사용하여 종속 모듈을 정의 할 수 있습니다.
[] 매개 변수가 없으면 새 모듈을 작성 하지 않고 기존 모듈을 검색 합니다.

 

 

controller

어플리케이션을 제어한다. 항상 모듈에 속함 
A controller is a JavaScript Object, created by a standard JavaScript object constructor

 

 

Directive

 

. directive함수를 사용하여 새 지시문을 만듭니다.
디렉티브의 이름을 지정할 때는 카멜 케이스 이름을 사용해야 w3TestDirective하지만
호출할 때는 -구분된 이름을 사용해야 합니다 w3-test-directive.

<body ng-app="myApp">         
<w3-test-directive></w3-test-directive>
<script>
var app = angular.module("myApp", []);
app.directive("w3TestDirective", function() {
  return {
    template : "<h1>Made by a directive!</h1>"                       //template-----HTML file
  };
});
</script>
</body>
<div w3-test-directive></div>

<div class="w3-test-directive"></div>
restrict : "C",
template : "<h1>Made by a directive!</h1>"

<!-- directive: w3-test-directive -->
return {
        restrict : "M",
        replace : true,
        template : "<h1>Made by a directive!</h1>"
    };

//The legal restrict values are:

//E for Element name  ()
//A for Attribute    (HTML 요소 )
//C for Class	(클래스)
//M for Comment   (주적)
//EA 기본값에 모든 지시문 호출 가능 
//By default the value is EA, meaning that both Element names and attribute names can invoke the directive.

 

AngularJS Filters

 

AngularJS provides filters to transform data:

currency: Format a number to a currency format.
date: Format a date to a specified format.
filter: Select a subset of items from an array.
json: Format an object to a JSON string.
limitTo: Limits an array/string, into a specified number of elements/characters.
lowercase: Format a string to lower case.
number: Format a number to a string.
orderBy: Orders an array by an expression.
uppercase: Format a string to upper case.

 

<p>The name is {{ lastName | uppercase }}</p>

<p><input type="text" ng-model="test"></p>
<ul>
  <li ng-repeat="x in names | filter : test">
    {{ x }}
  </li>
</ul>

 

 

 

$location

$location서비스에는 현재 웹 페이지의 위치에 대한 정보를 반환하는 메서드가 있습니다.

 

<h3>{{myUrl}}</h3>
var app = angular.module('myApp', []);
app.controller('customersCtrl', function($scope, $location) {
    $scope.myUrl = $location.absUrl();
});

 

$http

.get 메서드는 $ http 서비스의 바로 가기 메서드입니다. 몇 가지 바로 가기 방법이 있습니다.

.delete()
.get()
.head()
.jsonp()
.patch()
.post()
.put()
위의 메서드는 모두 $ http 서비스를 호출하는 바로 가기입니다.

var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $http) {
  $http.get("welcome.htm")
  .then(function(response) {
    $scope.content = response.data;
    $scope.statuscode = response.status;
    $scope.statustext = response.statusText;
  });
});


.config 요청을 생성하는 데 사용되는 개체입니다.
.data 서버에서 응답을 전달하는 문자열 또는 객체.
.headers 헤더 정보를 얻기 위해 사용하는 함수.
.status HTTP 상태를 정의하는 숫자.
.statusText HTTP 상태를 정의하는 문자열.

 

 

Directive(디렉티브)

ng-app 
AngularJs를 정의    예)) <div ng-app="">   자동 초기화
Angular에게 body 요소가 Anuglar 어플리케이션에 포함되어 있다고 알려준다. 즉, body 요소 내의 모든 것을 Angular 어플리케이션이 관리하도록 한다.
ng-model 
html input, select, textarea와 같은 입력 요소(UI, View)에 값을 갱신하며, 해당 변수(Model)의 값도 변한다. 
반대로 data 변수 ( Model) 값이 바뀌면, 화면 (View)도 바뀐다.
바로바로 갱신 
애플리케이션 데이터에 대한 유형 유효성 검사를 제공합니다 (번호, 이메일, 필수).
애플리케이션 데이터의 상태를 제공합니다 (유효하지 않음, 더티, 터치됨, 오류).
HTML 요소에 대한 CSS 클래스를 제공합니다.
HTML 요소를 HTML 양식에 바인딩합니다.
뷰를 변경하면 모델과 컨트롤러가 업데이트됩니다.
HTML (입력, 선택한 텍스트 영역)의 값을 결합한다.
애플리케이션 변수의 입력 필드의 값으로 이름 결합

ng-empty
ng-not-empty
ng-touched
ng-untouched
ng-valid
ng-invalid
ng-dirty
ng-pending
ng-pristine

ng-bind
html elements 내용 값을 바꾸는 데 사용. (inner HTML)  나타내는 부분
{{ expression }}.        ng-bind="expression".  같은 표현식

ng-controller
이 디렉티브를 사용하면 해당 요소의 스코프를 컨트롤러에 할당한다.

ng-init
초기값 설정  일반적으로 ng-init를 사용하지 않습니다. 대신 컨트롤러 또는 모듈을 사용합니다.

 

ng-repeat

<div ng-app="" ng-init="names=[
{name:'Jani',country:'Norway'},
{name:'Hege',country:'Sweden'},
{name:'Kai',country:'Denmark'}]">

<ul>
  <li ng-repeat="x in names">
    {{ x.name + ', ' + x.country }}
  </li>
</ul>

</div>


ng-show

<form ng-app="" name="myForm">
  Email:
  <input type="email" name="myAddress" ng-model="text">
  <span ng-show="myForm.myAddress.$error.email">Not a valid e-mail address</span>
</form>
ng-show속성 의 표현식이을 반환 하는 경우에만 표시됩니다 true.

 

ng-그외

ng-blur
ng-change
ng-click
ng-copy
ng-cut
ng-dblclick
ng-focus
ng-keydown
ng-keypress
ng-keyup
ng-mousedown
ng-mouseenter
ng-mouseleave
ng-mousemove
ng-mouseover
ng-mouseup
ng-paste

업로드


testMapper.xml

((((디비 테이블에file_name varchar(40)넣기))))

<!--게시글 삽입 -->
	<insert id="insertTest" parameterType="TestVO">
		<![CDATA[
		INSERT INTO test(testTitle, testContent, testName, testDate, fileName)
		VALUES(#{testTitle}, #{testContent}, '밥샵', now(), #{fileName})
		]]>
	</insert>

	<!--게시글 클릭시 detailView -->
	<select id="selectDetail"
		parameterType="egovframework.example.test.domain.TestVO"
		resultType="egovframework.example.test.domain.TestVO">
		<![CDATA[
			SELECT *
			FROM test
			WHERE testId = #{testId}
		]]>
	</select>

	<!--게시글 업데이트 -->
	<update id="updateTest">
		update test set
		testTitle = #{testTitle}
		,testContent = #{testContent}
		,fileName = #{fileName}
		where
		testId = #{testId}
	</update>

pom.xml

<!-- file upload -->
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.3.1</version>
		</dependency>

		<!-- MultipartHttpServletRequset -->
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.6</version>
		</dependency>

 


dispatcher-servlet.xml

<!-- 파일 업로드 설정 -->
	<bean id="multipartResolver"
		class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<!-- 파일 사이즈 설정 가능 byte 단위
		<property name="maxUploadSize" value="100000" />
		-->
	</bean>

testRegister.jsp

<tr>
	<th>첨부파일:</th>
	<td><input type="file" name="uploadFile"></td>	
</tr>

TestController

 

package egovframework.example.test.web;

import java.io.File;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import egovframework.example.test.domain.Search;
import egovframework.example.test.domain.TestVO;
import egovframework.example.test.service.TestService;

@Controller
public class TestController {

	@Autowired
	private TestService testServiceImpl;

	// 글 목록 리스트, 페이징, 검색
	@RequestMapping(value = "/testList.do")
	public String testListDo(Model model, @RequestParam(required = false, defaultValue = "1") int page,
			@RequestParam(required = false, defaultValue = "1") int range,
			@RequestParam(required = false, defaultValue = "testTitle") String searchType,
			@RequestParam(required = false) String keyword, @ModelAttribute("search") Search search) throws Exception {

		// 검색
		model.addAttribute("search", search);
		search.setSearchType(searchType);
		search.setKeyword(keyword);

		// 전체 게시글 개수를 얻어와 listCnt에 저장
		int listCnt = testServiceImpl.getBoardListCnt(search);

		// 검색
		search.pageInfo(page, range, listCnt);
		// 페이징
		model.addAttribute("pagination", search);
		// 게시글 화면 출력
		model.addAttribute("list", testServiceImpl.selectTest(search));

		return "test/testList";
	}

	// 글 작성 클릭시 글 작성 페이지로 이동
	@RequestMapping(value = "/testRegister.do")
	public String testRegister() {
		return "test/testRegister";
	}

	// 글 작성 버튼 구현
	@RequestMapping(value = "/insertTest.do")
	public String write(@ModelAttribute("testVO") TestVO testVO, RedirectAttributes rttr) throws Exception {

		// 파일 업로드 처리
		String fileName = null;
		MultipartFile uploadFile = testVO.getUploadFile();
		if (!uploadFile.isEmpty()) {
			String originalFileName = uploadFile.getOriginalFilename();
			String ext = FilenameUtils.getExtension(originalFileName); // 확장자 구하기
			UUID uuid = UUID.randomUUID(); // UUID 구하기
			fileName = uuid + "." + ext;
			uploadFile.transferTo(new File("C:\\upload\\" + fileName));
		}
		testVO.setFileName(fileName);

		testServiceImpl.insertTest(testVO);

		return "redirect:testList.do";
	}

	// HttpServletRequest 객체안에 모든 데이터들이 들어가는데 getParameter메소드로 testId 원하는 데이터 가져옴
	// 제목 클릭 시 상세보기
	@RequestMapping(value = "/testDetail.do")
	public String viewForm(@ModelAttribute("testVO") TestVO testVO, Model model, HttpServletRequest request)
			throws Exception {

		int testId = Integer.parseInt(request.getParameter("testId"));
		testVO.setTestId(testId);

		TestVO resultVO = testServiceImpl.selectDetail(testVO);
		model.addAttribute("result", resultVO);

		return "test/testDetail";
	}

	// 수정하기
	@RequestMapping(value = "/updateTest.do")
	public String updateTest(@ModelAttribute("testVO") TestVO testVO, HttpServletRequest request) throws Exception {
		// 파일 업로드 처리
		String fileName = null;
		MultipartFile uploadFile = testVO.getUploadFile();
		if (!uploadFile.isEmpty()) {
			String originalFileName = uploadFile.getOriginalFilename();
			String ext = FilenameUtils.getExtension(originalFileName); // 확장자 구하기
			UUID uuid = UUID.randomUUID(); // UUID 구하기
			fileName = uuid + "." + ext;
			uploadFile.transferTo(new File("C:\\upload\\" + fileName));
		}
		testVO.setFileName(fileName);
		testServiceImpl.updateTest(testVO);
		return "redirect:testList.do";
	}

	// 삭제하기
	@RequestMapping(value = "/deleteTest.do")
	public String deleteTest(@ModelAttribute("testVO") TestVO testVO) throws Exception {
		testServiceImpl.deleteTest(testVO);
		return "redirect:testList.do";
	}

}

TestVO

	private String fileName;
	private MultipartFile uploadFile;

다운로드

 


FileDownController.java

package egovframework.example.test.web;

import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class FileDownController {
     
    @RequestMapping(value = "fileDownload.do")
    public void fileDownload4(HttpServletRequest request,HttpServletResponse response) throws Exception {
        //String path =  request.getSession().getServletContext().getRealPath("저장경로");
        
        String filename =request.getParameter("fileName");
        String realFilename="";
        System.out.println(filename);
         
        try {
            String browser = request.getHeader("User-Agent"); 
            //파일 인코딩 
            if (browser.contains("MSIE") || browser.contains("Trident")
                    || browser.contains("Chrome")) {
                filename = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+",
                        "%20");
            } else {
                filename = new String(filename.getBytes("UTF-8"), "ISO-8859-1");
            }
        } catch (UnsupportedEncodingException ex) {
            System.out.println("UnsupportedEncodingException");
        }
        realFilename = "C:\\upload\\" + filename;
        System.out.println(realFilename);
        File file1 = new File(realFilename);
        if (!file1.exists()) {
            return ;
        }
         
        // 파일명 지정        
        response.setContentType("application/octer-stream");
        response.setHeader("Content-Transfer-Encoding", "binary;");
        response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
        try {
            OutputStream os = response.getOutputStream();
            FileInputStream fis = new FileInputStream(realFilename);
 
            int ncount = 0;
            byte[] bytes = new byte[512];
 
            while ((ncount = fis.read(bytes)) != -1 ) {
                os.write(bytes, 0, ncount);
            }
            fis.close();
            os.close();
        } catch (Exception e) {
            System.out.println("FileNotFoundException : " + e);
        }
    }
}

testDetail.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 uri="http://www.springframework.org/tags" prefix="spring"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!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">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet"
	href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
	integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
	crossorigin="anonymous">

<!-- Optional theme -->
<link rel="stylesheet"
	href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css"
	integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp"
	crossorigin="anonymous">

<!-- Latest compiled and minified JavaScript -->
<script
	src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
	integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
	crossorigin="anonymous"></script>
<link href="/css/test/test.css" rel="stylesheet" type="text/css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
</head>
<body>
	<div class="container">
		<table class="table table-bordered">
			<thead>
				<h1>글 상세보기 Detail</h1>
			</thead>
			<tbody>
				<form action="updateTest.do" id="viewForm" method="post"
					encType="multipart/form-data">
					<tr>
						<th>글번호:</th>
						<td><input name="testId" type="text" value="${result.testId}"
							class="form-control" readonly /></td>

					</tr>
					<tr>
						<th>제목:</th>
						<td><input type="text" value="${result.testTitle}"
							name="testTitle" class="form-control" /></td>
					</tr>
					<tr>
						<th>내용:</th>
						<td><textarea name="testContent" class="form-control"
								style="height: 200px;">${result.testContent}</textarea></td>

					</tr>
					<tr>
						<c:if test="${result.fileName ne null}">
							<tr>
								<td>다운로드</td>

								<td><a href="fileDownload.do?fileName=${result.fileName}">
										<input type="text" id="asd" value="${result.fileName}"
										name="fileName" class="form-control" readonly />
								</a>
									<button id="asdasd" type="button" class="btn_previous">파일지우기</button>
							</tr>
						</c:if>
					</tr>


					<tr>
						<th>첨부파일:</th>
						<td><input type="file" name="uploadFile"></td>
					</tr>
					<tr>

						<td colspan="2">
							<button id="btn_previous" type="button" class="btn_previous">이전</button>
							<button id="btn_delete" type="button" class="btn_previous">삭제</button>
							<button id="btn_modify" type="button" class="btn_register">수정</button>
					</tr>
				</form>
			</tbody>
		</table>
	</div>


</body>
<script type="text/javascript">
	$(document).on('click', '#btn_modify', function(e) {
		if (confirm("정말 수정하시겠습니까 ?") == true) {
			$("#viewForm").submit();
		} else {
			return;
		}

	});
	$(document).on('click', '#btn_delete', function(e) {
		if (confirm("정말 삭제하시겠습니까 ?") == true) {
			$("#viewForm").attr("action", "deleteTest.do");
			$("#viewForm").submit();
		} else {
			return;
		}

	});

	//이전 클릭 시 testList로 이동
	$("#btn_previous").click(function javascript_onclikc() {

		$(location).attr('href', 'testList.do');

	});
	$("#asdasd").click(function javascript_onclikc() {
		$('#asd').val(null);

	});
</script>
</html>

파일 업로드와 파일 다운로드, 파일 삭제를 구현하였다.

 

 

참고블로그

extsdd.tistory.com/category/IT/Spring(spring의 좋은 설명)

gangnam-americano.tistory.com/3

ming9mon.tistory.com/65?category=825118

freehoon.tistory.com/104

haenny.tistory.com/67(egov 게시판 sample예제 삭제)

badstorage.tistory.com/13(게시글 목록 갯수 변경)

lemontia.tistory.com/408?category=993095 (mapper namespace)

 

 

 

+ Recent posts