<h1>Ajax 개요</h1>
<p>
Ajax는 Asynchronous Javascript And XML이란 용어로<br> 서버로부터 데이터를 가져와 전체
페이지를 새로 고치지 않고 일부만 로드할 수 있게 하는 기법<br> 비동기식 요청을 함.
</p>
<h3>동기식/비동기식이란?</h3>
<p>
동기식은 서버와 클라이언트가 동시에 통신하여 프로세스를 수행 및 종료까지 같이하는 방식<br> 이에 반해 비동기식은
페이지 리로딩없이 서버요청 사이사이 추가적인 요청과 처리 가능
</p>
<script >
function jsFunc(){
//1. XMLHttpRequest객체 생성
var xhttp = new XMLHttpRequest();
var msg=document.querySelector("#msg-1").value;
//2. 요청정보 설정
xhttp.open("GET","/ajax/ex1.kh?msg="+msg,true);
//3. 데이터 처리에 따른 동작 함수 설정
xhttp.onreadystatechange = function(){
if(this.readyState=4 && this.status==200){
//status -> 200(요청성공), 404(페이지,url없음), 500(서버오류발생),403(접근거부),400(쿼리스트링 갯수오류)
console.log("서버 전송 성공");
}else if(this.readyState==4 && this.status ==400){
console.log("서버 전송 실패");
}
}
//4.전송
xhttp.send();
}
</script>
@ResponseBody
@RequestMapping(value="/ajax/ex1.kh", method=RequestMethod.GET)
public void exerciseAjax1(
@RequestParam("msg") String msg) {
System.out.println("전송 받은 데이터 : " + msg);
}
CREATE TABLE REPLY_TBL(
REPLY_NO NUMBER PRIMARY KEY,
REF_BOARD_NO NUMBER NOT NULL,
REPLY_CONTENTS VARCHAR2(500) NOT NULL,
REPLY_WRITER VARCHAR2(30) NOT NULL,
R_CREATE_DATE DATE DEFAULT SYSDATE,
R_UPDATE_DATE DATE DEFAULT SYSDATE,
R_STATUS VARCHAR2(2) DEFAULT 'Y'
);
CREATE SEQUENCE SEQ_REPLY_NO;
테이블 만들고. 댓글의 시퀀스도 만들어 준다.
controller에 댓글 입력부분 만들기.
@RequestMapping(value="/board/addReply.kh", method=RequestMethod.POST)
public ModelAndView addBoardReply(
ModelAndView mv
, @ModelAttribute Reply reply
,HttpSession session
, @RequestParam(value = "page", required = false) int page) {
//INSERT INTO REPLY_TBL VALUES(#{replyNo}=시퀀스,#{refBoardNo},#{replyContents},#{replyWriter},DEFAULT,DEFAULT,DEFAULT
Member member=(Member)session.getAttribute("loginUser");
String replyWriter=member.getMemberId();
reply.setReplyWriter(replyWriter);
int result=bService.registerReply(reply);
if(result>0) {
mv.setViewName("redirect:/board/detail.kh?boardNo="+reply.getRefBoardNo()); //+"&page="page
}
mv.addObject("page",page);
return mv;
}
session의 기록된 로그인 정보 가져오는것.......잊으면안됨...로그인정보는 어디서든 쓰이니깐..
<!--fetch('css') css를 바꾸면 경고창의 내용이 바뀐다. text에 서버가 응답한 결과가 들어가 있다. 결국은 실제 받은 값이다. 화면에 내용을 바꾸고 싶다면 input을 article로 감싸고. alert(text)을 document.querySelector('article').innerHtml=text; 화면출력함. css이후 then이하는 한절인데 일끝나면 내가 시킨 일을 해줘...함수를 처리해줘... callback함수를 기재해서 일을 시키는 것임. //이런걸 Asynchronous라고 함.////
이런걸 비동기!! 방식 순차적으로 끝날때 까지 기다리지 않고 먼저 되는것 먼저하기.....^^
fetch('html').then(callbackme); function callbackme(){}함수나 callbackme = function{} 나 같은 것이다.그래서 이름 없이 쓴다고 쓰는 익명함수!!! fetch('html'), then(function(){}) 이렇게 쓸수 있다.
function(response)){의 response는 response라는 객체가 오고 그중 status:값을 주는데 정상이면 200,
404를 주면 not found 찾을수가 없다는 값이다. 확인원하면 response.status라고 alert안에 기재하면 값이 나온다. fetch('css').then(function(response)){ if(response.status=='404'){ alert('Not found') } });
이런 방식도 있다.
///////////////////////////////////
반복되는 경우 당연히 스크립트로 함수 재활용 하면 된다. function fecthPage(name){ fetch('name').then(function(response){ response.text().then(function(text){ document.querySelectior('article').innerHTML = text; }) }); } name변수 값을 전달받은 fecthPage메서드를 호출하면
name파일로 값요청을 하고 서버로 부터 response 응답하면 text:값을 받아 article 태그안에 text값을 넣어주는 것이다.
/////////////////////////////////////////////////////// 북마크..... 내가 원하는 p태그에 id값을 준다. ex: id=three 그럼 주소창 localhost:8000/hash.html#three라고 하면 스크롤이 id가 있는 곳으로 이동을 한다.
또는 a 태그 에 href="#three" 라고 하고 화면에 a태그 글자를 입력하며 마찬가지로 스크롤이 이동한다. 시작하는 페이지를 우리가 선택할수 있다. <script> if(window.location.hash){ console.log(location.hash); // 이러면 해시값 #three가 출력된다... //#값을 없애고 싶으면 location.hash.substr(1)); 로 기재하면 된다.(window 은 생략가능함) } } a 태그를 클릭하면 주소창에는 </script> localhost:8000/hash.html#three 이렇게 나옴..
<a href="#!javascript" onclick="fetchPage('javascript')">HTML</a> // #해쉬기호라 !뱅을 관습처럼 붙여서 해쉬뱅이라고 하기도 함 a 태그를 클릭하면 주소창은 localhost:8000/hash.html#javascript 라고 나옴
if(location.hash){ //해시태그가 있다면 fetchPage(location.hash.substr(2)); // 2번째를 자르고 }else{ //없으면 fetchPage('welcome'); // welcome파일로 가라 } 그런데 이것은 새로고침이 아니라서 데이터 검색에서는 좋치 않아 좀더 보완한 pjax를 한다. //////////////////////////////////////////////// 홈페이지를 고치는 것보다 뒷배경의 파일의 정보만 추가하면되는 ...화면에 내용이 바꿀때.... 해더부분 추가할때 처럼 말이다.
예를 들어보자.!!!!! 실제 html이나 jsp에는 <ol id="nav"></ol> 밖에는 없었다.
fetch('list').then(function(response){ // 리스트의 파일의 response.text().then(function(text){ //text값을 받아온다. //<li> <a href="#!javascript" onclick="fetchPage('javascript')">HTML</a></li> //이렇게 너무 많아서 중복된게 너무 많다.....그래서 list파일에 html,css,jsvascript만 남기고 모두 삭제한다면 var items= text.split(',') //,를 기준으로 값을 배열화 시킨다. var i=0; //for문의 변수 var tags=''; //태그를 담을 그릇
while( i< items.length){ //배열이니깐 for문 돌린다. var item=items[i]; //각각의 배열값을 담을 변수 item=item.trim(); //변수에 혹시 빈칸같은것이 있다면 삭제해라. i=i+1; var tag='<li> <a href="#!'+item+'" onclick="fetchPage(\''+item+'\')">'+item+'</a></li>'; tags += tag; } //document.querySelectior('#nav').innerHTML = text; // id nav라는 태크안에 넣어라.란 뜻이다. document.querySelectior('#nav').innerHTML =tags; //링크까지 붇은 구문이 출력된다. }) }); ///////////////////////////////////////////////////////////////////////////////////////////// polyfill
== 신기능을 브라우저가 예전버전에서 지원하지 않기 때문에 대신 지원해주는 기능이다. fetch기능도 18년도 촬영기준으로 IF11버전은 미지원했다... 그래서 fetch.js라는 파일을 다운로드하여 저장함 그럼 크롬 말고 IF도 가능해서 호환성 확보 한것이다. -->
@Override
public Board printOneByNo(int boardNo) {
Board board= bStore.selectOneByNo(session, boardNo);
//게시글을 상세조회하면 조회수 추가를 위한 부분
int result=0;
if(board!=null) {
result=bStore.updateBoardCount(session,boardNo);
}
return board;
}
store -> toss
// 조회수 만드는 부분
@Override
public int updateBoardCount(SqlSessionTemplate session, int boardNo) {
int result=session.update("BoardMapper.updateCount",boardNo);
return result;
}
사실 리턴값이 필요 한것은 아니라서 의미는 없지만 혹시 모르니깐 같이 진행한다..
<!-- 조회수 관련 업데이트 -->
<update id="updateCount">
UPDATE BOARD_TBL SET BOARD_COUNT = BOARD_COUNT + 1 WHERE BOARD_NO=#{boardNo}
</update>
<script>
function boardRemove(page) {
event.preventDefault();// 하이퍼 링크 이동 방지
if(confirm("게시물을 정말 삭제하시겠습니까?")){
location.href="/board/remove.kh?page="+page;
}
}
</script>
상세페이지에 목록 다 하고 마지막 삭제하기 정말할때 페이지 값을 함수로 해서 다시 보내준다.
public String boardRemove(HttpSession session, Model model,
@RequestParam("page") Integer page) {
// 삭제만 하니깐..ModelAndView가아니라 그냥 String 반환에 model연결함
try {
int boardNo = (int) session.getAttribute("boardNo");
int result = bService.removeOnebyNo(boardNo);
if (result > 0) {
session.removeAttribute("boardNo");
// 성공해서 삭제되었으니깐 세션에서 정보를 삭제해야함
}
//model.addAttribute("page", page);
return "redirect:/board/list.kh?page="+page;
} catch (Exception e) {
model.addAttribute("msg",e.toString());
return "common/errorPage";
}
}
@RequestParam("page") Integer page) 함수로 받으니깐 표현이 조매 다름...
삭제 후 다시 mv로 리스트 조회로 보낼때 다시 페이지를 보낸다.
삭제가 되었다......
public ModelAndView boardModify(@ModelAttribute Board board, ModelAndView mv,
@RequestParam(value = "reloadFile", required = false) MultipartFile reloadFile // 위에서 upload였는데 여기선
,@RequestParam("page")Integer page // reloadFile로 변경
, HttpServletRequest request) {
try {
String boardFilename = reloadFile.getOriginalFilename();
if (reloadFile != null && !boardFilename.equals("")) {
// 파일 이 있거나, 파일명이 있을때
// 수정방법 = 1, 대체 2, 삭제 후 저장 ==>삭제후 저장이 오히려 편함
// 파일 경로를 알아야 한다. 리케스트 필요 httpHttpServletRequest request
// 파일 삭제
String root = request.getSession().getServletContext().getRealPath("resources");
String savedPath = root + "\\buploadFiles";
// 파일이름을 갖고 오고자 db로 갈필요는 없음. 이 jsp에 board 자료가 있음
File file = new File(savedPath + "\\" + board.getBoardFileRename());// file.io
if (file.exists()) { // 파일이 정말 있는지 확인
file.delete(); // 파일 지움
}
// 삭제 했으니깐 다시 저장
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String boardFileRename = sdf.format(new Date(System.currentTimeMillis())) + "."
+ boardFilename.substring(boardFilename.lastIndexOf(".") + 1);
// substring 때문에 1을 더한것임
// lastIndexOf(".")은 파일.뒤의 확장자 구하는 것이다.
String boardFilepath = savedPath + "\\" + boardFileRename;
reloadFile.transferTo(new File(boardFilepath));
board.setBoardFilename(boardFilename);
board.setBoardFileRename(boardFileRename);
board.setBoardFilepath(boardFilepath);
}
int result = bService.modifyBoard(board);
mv.setViewName("redirect:/board/list.kh?page="+page);
수정할때는 약간다르다.....
,@RequestParam("page")Integer page
mv.setViewName("redirect:/board/list.kh?page="+page);// 이건 전송방식이 조금 다르지만 응용이다.
<!-- 주소api를 쓰기 위한 스크립트 -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="//d1p7wdleee1q2z.cloudfront.net/post/search.min.js"></script>
<script>
/* 주소api구간 */
$("#postcodify_search_button").postcodifyPopUp();
</script>
스크립트 넣어야지~~~~
public ModelAndView memberJoin( //스프링에서 모델과 뷰를 합쳐좋은 클래스이다.
@ModelAttribute Member member
// @ModelAttribute하나로 하단 @RequestParam 의 변수 값 받는 것을 모두 퉁칠수 있다. 대신에 input에 name과 변수명이 동일해야함. 아주 중요
//명칭이 다르면 Member 객체에서 그 값은 안들어감...
// @RequestParam("memberId") String memberId //form의 input의 name값 // 틀리면 안됨
// , @RequestParam("memberPwd") String memberPwd
// , @RequestParam("memberName") String memberName
// , @RequestParam("memberEmail") String memberEmail
// , @RequestParam("memberPhone") String memberPhone
, @RequestParam("post") String post
, @RequestParam("address1") String address1
, @RequestParam("address2") String address2
// , Model model
, ModelAndView mv){
//request.setCharacherEncoding("utf-8"); 할수도 있으나 그럼 매번 사용해줘야 함으로 필터로 진행하기로 함.
try {
// Member member=new Member(memberId,memberPwd, memberName, memberEmail,memberPhone, post+","+memberAddress);
// @ModelAttribute("") 덕분에 위에것을 다래 것으로 간단히 기재하면 된다.
member.setMemberAddr(post+","+address1+"/"+address2);
controller 에 param값 불러온것을 또 한가지로 합친다.... 샘은 ,로 했는데 나중에 수정시 불러오기 있을것 같아...한번더 체크