AJAX(Asynchronous JavaScript And Xml)
- 비동기로 통신하는 JavaScript(JSON)와 xml
- 동기화 : 요청한 후 응답이 올 때 까지 다른 작업 불가능 ex) 웨이팅
- 비동기화: 요청 후 응답이 올 때 까지 다른 작업 가능 ex) 테이블링 서비스
- 요청을 받아서 전달하고 요청이 처리되면 응답을 날려주는 존재가 있음
# 보안이 필요한 것들은 ajax 사용 지양
ajax 메소드 - $.ajax({});
- {} : object 객체 넣을때 사용(key,value)
$.ajax({ | |
type:"get", | 전송 방식을 GET 으로 지정. [POST | GET] |
url:”http://localhost:8080/api”, | 요청을 전송 할 url 주소 |
data:{ q:qry, result:10, ... }, | 요청시 추가할 파라메터 |
dataType:"JSON", | 응답 받을 데이터 타입[json | xml | text | jsonp] |
timeout:5000, | 요청 타임 아웃(milliseconds) |
success: function(data){}, | 성공 시 실행 할 내용(data : 응답 받은 데이터) |
error:function(request,status,error){} | 실패 시 실행 할 내용 |
}); |
# timeout 외에는 필수로 작성되어야 함
Ajax 흐름도
- Ajax를 통해 일반적으로 text, json, xml 등을 사용 할 수 있음
- Controller를 통하지 않고 다른 html을 불러 올 수도 있음
Form 방식과 Ajax 방식의 차이점
Form | Ajax |
다른 페이지로 데이터 이동이 가능 | 다른 페이지로 데이터 이동이 불가능 |
페이지를 다시 호출해야 함 | 페이지를 다시 호출 할 필요가 없음(기존 html에 덮어쓰기 때문) 기존 페이지의 내용을 유지시킴 |
실시간으로 데이터를 부르기에 부적합 | 실시간으로 데이터를 부르기에 적합(기존 html에 덮어쓰기 때문) |
Multi-part request를 전송할 수 있음 | Multi-part request를 전송하기 어려움(IE 8 기준) |
Ajax 라이브러리
- https://mvnrepository.com에서 다운로드
- Jackson Databind : Jackson Databind 2.9.4
- jackson-core 라이브러리의 의존성을 포함하기 때문에 jackson-core 없이도 가능
- 자바의 object와 ajax에서 사용하는 jackson 타입을 서로 주고받을 수 있도록 변환시켜줌
- file, url, string 형태로 데이터를 읽어올 수 있음
- Jackson Core : https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core 2.9.4
- ajax 실행 라이브러리
Ajax만 사용해서 로그인&팝업 시스템 만들기(DB사용 X)
- pom.xml에 위의 라이브러리 추가하기
- DB사용하지 않을것이기 때문에 DB라이브러리 추가X
<!-- JSON 관련 LIBRARY -->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.4</version>
</dependency>
- AjaxController
package kr.co.gudi.controller;
import java.util.HashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class AjaxController {
Logger logger = LoggerFactory.getLogger(getClass());
@RequestMapping(value="/")
public String home() {
return "login";
}
//비동기방식 특징
//1. response를 이용(request 사용못함)
//2. 데이터를 request에 담을 수 없기 때문에 response에 새겨야 함
//3. 다른 페이지로 데이터 전송 불가능(단점)
@RequestMapping(value="/login.ajax")
@ResponseBody
public HashMap<String, Object> login(@RequestParam String id, @RequestParam String pw) {
logger.info("params : "+id+"/"+pw);
//id가 admin이고 pw가 pass면 success: true
//아니면 success: false
boolean success = false;
if(id.equals("admin") && pw.equals("pass")) {
success = true;
}
//view에 msg 내려보내기
//map.put("msg", "응답완료!");
// >> success로 내려보내기
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("success", success);
return map;
}
@RequestMapping(value="/main.go")
public String mainPage() {
return "main";
}
}
- main.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<style>
table,th,td{
border: 1px solid black;
border-collapse: collapse;
padding: 5px 10px;
}
div.floating{
position: absolute;
width: 200px;
height: 100px;
text-align: center;
border: 1px solid black;
background-color: lightgray;
top: 25%;
left: 35%;
}
</style>
</head>
<body>
<h3>ajax로 html 내용 읽어오기</h3>
</body>
<div id="listArea"></div>
<button id="popup1">1번 팝업</button>
<button id="popup2">2번 팝업</button>
<button id="popup3">3번 팝업</button>
<div id="noticeArea"></div>
<script>
//ajax로 다른 html 불러오기
$.ajax({
type:'get',
url:'resources/html/list.html',
dataType:'html',
success:function(data){
console.log(data);
$('#listArea').html(data);
},
error:function(e){
console.log(e);
}
});
$('button').click(function(e){
//불러올 html 주소, call back function(없어도됨)
console.log(e.target.id); //this도 사용가능
$('#noticeArea').load('resources/html/notice.html #'+e.target.id,
function(res,stat){
console.log(res); //전체소스
console.log(stat);//불러오기 성공|실패 여부
});
});
</script>
</html>
# 삽입할 html은 resources 폴더 하위에 html 폴더 생성 후 넣어주었음(jsp에서 경로 작성한 후불러서 사용)
- list.html
<table>
<tr>
<th>글번호</th>
<th>내용</th>
</tr>
<tr>
<th>3</th>
<th>어떤 글의 제목입니다.</th>
</tr>
<tr>
<th>2</th>
<th>어떤 글의 제목입니다.</th>
</tr>
<tr>
<th>1</th>
<th>어떤 글의 제목입니다.</th>
</tr>
</table>
- notice.html
<div class="floating" id="popup1">
404 에러입니다.
</div>
<div class="floating" id="popup2">
500 에러입니다.
</div>
<div class="floating" id="popup3">
400 에러입니다.
</div>
Ajax만 사용해서 로그인&회원가입 시스템 만들기(DB사용)
- login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<link rel="stylesheet" href="resources/css/common.css" type="text/css">
<style>
</style>
</head>
<body>
<h3>로그인</h3>
<table>
<tr>
<th>아이디</th>
<td><input type="text" id="id"/></td>
</tr>
<tr>
<th>비밀번호</th>
<td><input type="password" id="pw"/></td>
</tr>
<tr>
<th colspan="2">
<button onclick="login()">로그인</button>
<button onclick="location.href='join.go'">회원가입</button>
</th>
</tr>
</table>
</body>
<script>
function login(){
var id = $('#id').val();
var pw = $('#pw').val();
//console.log(id,pw);
$.ajax({
type:'post',
url:'login.ajax',
data:{
id:id,
pw:pw
},
dataType:'json',
success:function(data){
//console.log(data);
if(data.success == 1){
alert('로그인에 성공했습니다.');
location.href='list.go';
}else{
alert('아이디 또는 비밀번호를 확인해주세요!');
}
},
error:function(e){
console.log(e);
}
});
}
</script>
</html>
- joinForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<link rel="stylesheet" href="resources/css/common.css" type="text/css">
<style>
#id{
width: 70%;
}
</style>
</head>
<body>
<h3>회원가입</h3>
<table>
<tr>
<th>아이디</th>
<td>
<input type="text" id="id"/>
<button id="overlay">중복체크</button>
</td>
</tr>
<tr>
<th>비밀번호</th>
<td><input type="password" id="pw"/></td>
</tr>
<tr>
<th>비밀번호 확인</th>
<td>
<input type="password" id="confirm"/>
<span id="msg"></span>
</td>
</tr>
<tr>
<th>이름</th>
<td><input type="text" id="name"/></td>
</tr>
<tr>
<th>나이</th>
<td><input type="text" id="age"/></td>
</tr>
<tr>
<th>성별</th>
<td>
<input type="radio" name="gender" value="남"/>남자
<input type="radio" name="gender" value="여"/>여자
</td>
</tr>
<tr>
<th>이메일</th>
<td><input type="text" id="email"/></td>
</tr>
<tr>
<th colspan="2">
<button onclick="join()">가입</button>
<button onclick="location.href='./'">돌아가기</button>
</th>
</tr>
</table>
</body>
<script>
var pweq = false;
var overlayChk = false;
function join(){
console.log('회원가입');
if(pweq && overlayChk){
var $id = $('#id');
var $pw = $('#pw');
var $name = $('#name');
var $age = $('#age');
var $gender = $('input[name="gender"]:checked');
var $email = $('#email');
console.log($gender);
if($id.val() ==''){
alert('아이디를 입력해주세요!');
$id.focus();
}else if($pw.val()==''){
alert('비밀번호를 입력해주세요!');
$pw.focus();
}else if($name.val()==''){
alert('이름을 입력해주세요!');
$name.focus();
}else if($age.val()==''){
alert('나이를 입력해주세요!');
$age.focus();
}else if($gender.val() == null){
alert('성별을 입력해주세요!');
}else{
console.log('회원가입 요청!');
//data에 많은 값들이 들어가면 복잡하기 때문에 따로 빼줌
var param = {};
param.id = $id.val();
param.pw = $pw.val();
param.name = $name.val();
param.age = $age.val();
param.gender = $gender.val();
param.email = $email.val();
console.log(param);
$.ajax({
type: 'post',
url:'join.ajax',
data:param,
dataType:'json',
success:function(data){
console.log(data);
if(data.success == 1){
alert('회원가입이 완료되었습니다.');
location.href='./';
}else{
alert('회원가입에 실패했습니다.\r\n다시 시도해주세요.');
}
},
error:function(e){
console.log(e);
alert('회원가입에 실패했습니다.\r\n다시 시도해주세요.');
}
});
}
}else{
alert('아이디 중복체크와 비밀번호 확인을 해주세요.');
}
}
$('#overlay').on('click',function(e){
var chkId = $('#id').val();
console.log('중복체크 요청 : '+chkId);
$.ajax({
type:'get',
url:'overlay.ajax',
data:{'id':chkId},
dataType:'json',
success:function(data){
console.log(data);
if(data.overlay == 0){
alert('사용가능한 아이디입니다.');
overlayChk = true;
}else{
alert('이미 사용중인 아이디입니다.');
}
},
error:function(e){
console.log(error);
}
});
});
$('#confirm').on('keyup',function(e){
/* var pw = $('#pw').val();
var input = $(this).val();
console.log(pw,input); */
if($('#pw').val() == $(this).val()){
console.log('일치함');
$('#msg').css({'font-size':'8px', 'color':'darkgreen'});
$('#msg').html('비밀번호가 일치합니다.');
pweq = true;
}else{
console.log('일치하지 않음');
$('#msg').css({'font-size':'8px', 'color':'red'});
$('#msg').html('비밀번호가 일치하지 않습니다.');
}
});
</script>
</html>
- list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<link rel="stylesheet" href="resources/css/common.css" type="text/css">
<style>
</style>
</head>
<body>
<h3>회원리스트</h3>
<button onclick="realTime()">실시간 감시</button>
<button onclick="del()">삭제</button>
<table>
<thead>
<tr>
<th><input type="checkbox" id="all" value=""/></th>
<th>아이디</th>
<th>이름</th>
<th>이메일</th>
</tr>
</thead>
<tbody id="list">
</tbody>
</table>
</body>
<script>
function realTime(){
setInterval(function(){
list();
},1000);
}
list();
function list(){
$.ajax({
type:'get',
url:'list.ajax',
data:{},
dataType:'json',
success:function(data){
if(!data.login){
alert('로그인이 필요한 서비스 입니다.');
location.href='./';
}else{
listDraw(data.list);
}
},
error:function(e){
console.log(e);
}
});
}
function listDraw(list){
//console.log(list);
var content ='';
/* list에 있는 것을 item으로 하나씩 꺼내서 각각 함수를 실행 */
list.forEach(function(item,index){
content +='<tr>';
content +='<td><input type="checkbox" value="'+item.id+'"/></td>';
content +='<td><a href="detail.go?id='+item.id+'">'+item.id+'</a></td>';
content +='<td>'+item.name+'</td>';
content +='<td>'+item.email+'</td>';
content +='<td><a href="#" onclick="del('+"\'"+item.id+"\'"+')">삭제</a></td>';
content +='</tr>';
});
$('#list').empty();
$('#list').append(content);
}
$('#all').click(function(e){
var $chk = $('input[type="checkbox"]');
console.log($chk);
if($(this).is(':checked')){
$chk.prop('checked',true);
}else{
$chk.prop('checked',false);
}
});
function del(id){
var checkArr = [];
$('input[type="checkbox"]:checked').each(function(idx,item){
//checkbox에 value를 지정하지 않으면 기본값을 on으로 스스로 지정함
if($(this).val()!='on'){
console.log(idx,$(this).val());
checkArr.push($(this).val());
}
});
console.log(checkArr);
$.ajax({
type:'get',
url:'delete.ajax',
data:{'delList':checkArr},
dataType:'json',
success:function(data){
console.log(data);
if(data.success){
alert(data.msg)
list();
}
},
error:function(e){
console.log(e);
}
});
}
</script>
</html>
- detail.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<link rel="stylesheet" href="resources/css/common.css" type="text/css">
<style>
#id{
width: 70%;
}
</style>
</head>
<body>
<h3>상세보기</h3>
<table>
<tr>
<th>아이디</th>
<td id="id"></td>
</tr>
<tr>
<th>비밀번호</th>
<td id="pw"></td>
</tr>
<tr>
<th>이름</th>
<td id="name"></td>
</tr>
<tr>
<th>나이</th>
<td id="age"></td>
</tr>
<tr>
<th>성별</th>
<td>
<input id="male" type="radio" name="gender" value="남"/>남자
<input id="female" type="radio" name="gender" value="여"/>여자
</td>
</tr>
<tr>
<th>이메일</th>
<td id="email"></td>
</tr>
<tr>
<th colspan="2">
<button onclick="location.href='./list.go'">돌아가기</button>
</th>
</tr>
</table>
</body>
<script>
$.ajax({
type:'get',
url:'detail.ajax',
data:{},
dataType:'json',
success:function(data){
console.log(data);
$('#id').html(data.id);
$('#pw').html(data.pw);
$('#name').html(data.name);
$('#age').html(data.age);
$('#email').html(data.email);
if(data.gender == '남'){
//attr : 정지된 속성
//prop : 동적인 속성(만들어진 요소)
$('#male').prop('checked',true);
}else{
$('#female').prop('checked',true);
}
},
error:function(e){
console.log(e);
}
});
</script>
</html>
- MemberController
package kr.co.gudi.member.controller;
import java.util.ArrayList;
import java.util.HashMap;
import javax.servlet.http.HttpSession;
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.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import kr.co.gudi.member.dto.MemberDTO;
import kr.co.gudi.member.service.MemberService;
@Controller
public class MemberController {
@Autowired MemberService service;
Logger logger = LoggerFactory.getLogger(getClass());
@RequestMapping(value="/")
public String home() {
//logger.info("로그인 페이지 이동");
return "login";
}
@RequestMapping(value="join.go")
public String joinForm() {
return "joinForm";
}
@RequestMapping(value="/overlay.ajax")
@ResponseBody
public HashMap<String, Object> overlay(@RequestParam String id){
logger.info("overlay id : "+id);
return service.overlay(id);
}
@RequestMapping(value="/join.ajax")
@ResponseBody
public HashMap<String, Object> join(@RequestParam HashMap<String, String> params){
logger.info("params : "+params);
return service.join(params);
}
@RequestMapping(value="/login.ajax")
@ResponseBody
public HashMap<String, Object> login(@RequestParam String id, @RequestParam String pw, HttpSession session){
//logger.info("id : {} / pw : {}",id,pw);
int success = service.login(id,pw);
//logger.info("success : "+success);
if(success == 1) {
session.setAttribute("loginId", id);
}
//logger.info("session : "+session.getAttribute("loginId"));
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("success", success);
return map;
}
@RequestMapping(value="/list.go")
public String list(HttpSession session) {
String page = "redirect:/";
if(session.getAttribute("loginId") != null) {
logger.info("로그인 여부 확인");
page = "list";
}
return page;
}
@RequestMapping(value="/list.ajax")
@ResponseBody
public HashMap<String, Object> listCall(HttpSession session){
boolean login = false;
HashMap<String, Object> map = new HashMap<String, Object>();
if(session.getAttribute("loginId") != null) {
login = true;
ArrayList<MemberDTO> list = service.list();
map.put("list",list);
}
map.put("login", login);
return map;
}
@RequestMapping(value="/delete.ajax")
@ResponseBody
public HashMap<String, Object> delete(@RequestParam(value="delList[]") ArrayList<String> delList){
//array로 받을 경우 @RequestParam에 value를 반드시 명시해야함
logger.info("delList:"+delList);
return service.delete(delList);
}
@RequestMapping(value="/detail.go")
public String detail(@RequestParam String id, HttpSession session) {
logger.info("deatil id : " +id);
session.setAttribute("detailId", id);
return "detail";
}
@RequestMapping(value="/detail.ajax")
@ResponseBody
public HashMap<String, Object> detail(HttpSession session){
String detailId = (String) session.getAttribute("detailId");
logger.info("상세보기할 아이디 : "+detailId);
HashMap<String, Object> map = service.detail(detailId);
if(map != null && map.size() > 0) {
logger.info("데이터를 가져오기 성공");
session.removeAttribute("detailId");
}
return map;
}
}
- MemberService
package kr.co.gudi.member.service;
import java.util.ArrayList;
import java.util.HashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import kr.co.gudi.member.dao.MemberDAO;
import kr.co.gudi.member.dto.MemberDTO;
@Service
public class MemberService {
@Autowired MemberDAO dao;
Logger logger = LoggerFactory.getLogger(getClass());
public HashMap<String, Object> overlay(String id) {
HashMap<String, Object> map = new HashMap<String, Object>();
//같은 아이디가 있으면 1, 없으면 0을 반환
map.put("overlay", dao.overlay(id));
return map;
}
public HashMap<String, Object> join(HashMap<String, String> params) {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("success",dao.join(params));
return map;
}
public int login(String id, String pw) {
return dao.login(id,pw);
}
public ArrayList<MemberDTO> list() {
return dao.list();
}
public HashMap<String, Object> delete(ArrayList<String> delList) {
HashMap<String, Object> map = new HashMap<String, Object>();
int delSize = delList.size();
int successCnt = 0;
for(String id : delList) {
successCnt += dao.delete(id);
}
map.put("msg", delSize+"개의 요청 중 "+successCnt+"개를 삭제했습니다.");
map.put("success", true);
return map;
}
public HashMap<String, Object> detail(String detailId) {
logger.info("detail service");
return dao.detail(detailId);
}
}
- MemberDAO
package kr.co.gudi.member.dao;
import java.util.ArrayList;
import java.util.HashMap;
import kr.co.gudi.member.dto.MemberDTO;
public interface MemberDAO {
int overlay(String id);
int join(HashMap<String, String> params);
int login(String id, String pw);
ArrayList<MemberDTO> list();
int delete(String id);
HashMap<String, Object> detail(String detailId);
}
- MemberDTO
package kr.co.gudi.member.dto;
public class MemberDTO {
private String id;
private String pw;
private String name;
private int age;
private String gender;
private String email;
//getter&setter 생략
}
- member_mapper.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.co.gudi.member.dao.MemberDAO">
<select id="overlay" resultType="int">
SELECT COUNT(id) FROM member WHERE id = #{param1}
</select>
<insert id="join" parameterType="hashmap">
INSERT INTO
member(id,pw,name,age,gender,email)
VALUES(#{id},#{pw},#{name},#{age},#{gender},#{email})
</insert>
<select id="login" resultType="int">
SELECT COUNT(id) FROM member WHERE id =#{param1} AND pw=#{param2}
</select>
<select id="list" resultType="kr.co.gudi.member.dto.MemberDTO">
SELECT id,name,email FROM member;
</select>
<delete id="delete">
DELETE FROM member WHERE id = #{param1}
</delete>
<select id="detail" resultType="hashmap">
SELECT * FROM member WHERE id = #{param1}
</select>
</mapper>
'코딩도전기 > Spring' 카테고리의 다른 글
AOP - Proxy Pattern (1) | 2023.12.30 |
---|---|
CODO Day46_Spring(Paging) (0) | 2023.04.07 |
CODO Day44_Spring(PhotoBoard) (0) | 2023.04.04 |
CODO Day43_Spring(FileService) (0) | 2023.04.03 |
CODO Day42_Spring(BoardApp) (0) | 2023.03.31 |