20220902_FRI
자바스크립트의 라이브러리.
비동기 통신(서로 데이터를 주고 받는 것)을 가능하게 해 줌.
- 동기 통신(지금까지 해온 것)
: 데이터를 주고 받는 시간이 같다.일련의 순서대로 진행이 된다.
: 화면 -> 컨트롤러(자바) -> 화면 ..(실행의 흐름)
: 페이지 이동해야 데이터를 보여줄 수 있어서, 상대적으로 부하가 생기고 느릴 수 밖에 없다.- 비동기 통신(ajax)
:화면 -> 컨트롤러 (페이지이동없이 이대로 끝)
:하나의 페이지에서만 보이기 때문에 페이지 이동없고 데이터를 로딩할 필요가 없어서 성능도 빨라지고 화면의 움직임이 부드럽게 보인다.
AjaxTest 스프링 프로젝트 생성
application.properties (기본 세팅 설정)
# PORT 포트
server.port=8081
# thymeleaf 캐쉬 설정
spring.thymeleaf.cache=false
#spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
#spring.datasource.url=jdbc:oracle:thin:@127.0.0.1:1521/xe
spring.datasource.driver-class-name=net.sf.log4jdbc.sql.jdbcapi.DriverSpy
spring.datasource.url=jdbc:log4jdbc:oracle:thin:@localhost:1521/xe
spring.datasource.username=MYDB
spring.datasource.password=ORACLE
#xml location
#mybatis.mapper-locations=classpath:mappers/**/*.xml
mybatis.mapper-locations=classpath:mappers/*.xml
- 패키지명:kh.study.ajax.controller
- 클래스명:AjaxController
@RestController
사용하여 경로설정시 html파일생성 별도로 필요없이 바로 리턴값 출력된다.
package kh.study.ajax.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import kh.study.ajax.vo.MemberVO;
@Controller
@RequestMapping("/ajax")
public class AjaxController {
@GetMapping("/ex1") //localhost:8081/ajax/ex1
public String test1() {
return "ex1";//페이지이동
}
//@ResponseBody 이 붙은 메소드는 실행 후 페이지이동하지 않는다!
//return에 이동할 페이지명을 작성하는게 아니라,필요한 데이터를 리턴하면 된다.
@ResponseBody
@PostMapping("/ex2") //localhost:8081/ajax/ex1
public List<MemberVO> test2() {
System.out.println("test2() 메소드 실행 된다.");
List<MemberVO> list = new ArrayList<>();
MemberVO vo1 = new MemberVO();
vo1.setName("김자바");
vo1.setAge(21);
vo1.setTell("010-1111-2221");
MemberVO vo2 = new MemberVO();
vo2.setName("이자바");
vo2.setAge(22);
vo2.setTell("010-1111-2222");
MemberVO vo3 = new MemberVO();
vo3.setName("박자바");
vo3.setAge(23);
vo3.setTell("010-1111-2223");
list.add(vo1);
list.add(vo2);
list.add(vo3);
//페이지이동하지않고 다시 자바스크립트 ajax_test.js로 가는데,이 리턴값은 result가 가져간다.
//return "hello";//String 일때
//return 100;//int 일때
//return vo;//MemberVO 자료형일때 객체리턴
return list;//객체리턴
}
@ResponseBody
@PostMapping("/ex3")
public void test3(MemberVO memberVO, String name, int age) {
//ajax에서 넘어어오는데이터랑 똑같이
//매개변수 membervo나 String name,int age로도 받아올수있다
System.out.println(memberVO.getAge());//20
System.out.println(memberVO.getName());//HongJava
}
}
localhost:8081
입력시 , return 값 test 화면 출력된다.package kh.study.ajax.vo;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class MemberVO {
private String name;
private int age;
private String tell;
}
Jquery문법 로딩
:jqury문법 로딩_ 먼저,ajax 스크립트문법 파일만든후, 제이쿼리로 자바스크립트 사용해야 가능하다
단, 순서가 중요하다! 문법로딩을 가장 먼저 사용 후, 뒤에 자바스크립트 코드를 사용가능하다!
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"><!-- jsp에서 foreach문 사용할때 lib태그 사용하는 것과 같다.앞으로 html 만들때는 사용해야한다. 원래 html만들때 next누르고 별도로 생성한 htnl_thymeleaf를 선택하면 자동생성된다-->
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
ex1<br>
<input type="button" value="실행1" onclick="test1();">
<input type="button" value="실행2" onclick="test2();">
<!--jqury문법 로딩: ajax 스크립트문법 파일만든후, 제이쿼리로 자바스크립트 사용 -->
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript" th:src="@{/ajax_test.js}"></script>
</body>
</html>
ajax 시작 문법
- ajax을 사용하여 페이지이동(html)없이 화면움직일 수 있다.
$.ajax({ url: '/ajax/ex2',type: 'post',data:{},success: function(result) {},error: function(){alert('실패');}});
function test1() {
//test1()실행되면 ajax실행되는데 url이 컨트롤러로 간다
//ajax start jquery
$.ajax({
url: '/ajax/ex2', //요청경로
type: 'post',//postMapping방식으로 위 url컨트롤러 찾아간다
data:{}, //필요한 데이터
success: function(result) {//result에 return값 들어온다
//자바스크립트의 콘솔
//ajax 데이터 뽑는 방법
console.log(result);
console.log(result.name);
console.log(result.age);
console.log(result.tell);
//list 일때
//데이터는 뽑는 방법 : result.name 안된다.
//그래서 반복문으로
//[for문]
/*for(let i = 0; i < result.length; i ++){
console.log(result[i].name);
console.log(result[i].age);
console.log(result[i].tell);
}*/
//[foreach문]
for(const member of result){
console.log(member.name);
console.log(member.age);
console.log(member.tell);
}
},
error: function(){
alert('실패');
}
});
//ajax end
}
function test2() {
//ajax start
$.ajax({
url: '/ajax/ex3', //요청경로
type: 'post',
// HongJava 라는 값을 name으로 데이터 던진다.
data:{'name':'HongJava', 'age':20}, //필요한 데이터
success: function(result) {
alert('aaa');
},
error: function(){
alert('실패');
}
});
//ajax end
}
실습내용
localhost:8081/stu/list
- 위 요청경로로 들어오면 학급목록과 학생목록정보가 화면에 나와야한다.
<생성 파일 목록>
- templates/stu_manage.html 파일 생성
- kh.study.ajax.service.StuService
- kh.study.ajax.service.StuServiceImpl
- kh.study.ajax.controller.StuController
- kh.study.ajax.vo.ClassVO
- kh.study.ajax.vo.ScoreVO
- kh.study.ajax.vo.StuVO
- 학급목록은 셀렉트박스에 나타난다.(단,셀렉트박스의 기본값은 전체로 한다)
- 셀렉트박스 밑에는 테이블로 학생 전체목록이 조회되면 된다.
- 학생목록은 학번,이름,나이,학급명을 조회한다.
- 화면은 양쪽분할로 테이블 1행 2열로 만들어 나타날수있도록 한다.
--Ajax 실습 테이블
--학급정보 테이블
CREATE TABLE CLASS_INFO(
CLASS_CODE NUMBER PRIMARY KEY
, CLASS_NAME VARCHAR2(100) NOT NULL
);
--학생테이블
CREATE TABLE STUDENT_INFO(
STU_NUM NUMBER PRIMARY KEY
, STU_NAME VARCHAR2(100) NOT NULL
, STU_AGE NUMBER
, CLASS_CODE NUMBER REFERENCES CLASS_INFO(CLASS_CODE)
);
-- 학생 점수 정보 테이블
CREATE TABLE SCORE_INFO(
SCORE_NUM NUMBER PRIMARY KEY
, KOR_SCORE NUMBER DEFAULT 0
, ENG_SCORE NUMBER DEFAULT 0
, MATH_SCORE NUMBER DEFAULT 0
, STU_NUM NUMBER REFERENCES STUDENT_INFO(STU_NUM)
);
INSERT INTO CLASS_INFO VALUES (1, '자바반');
INSERT INTO CLASS_INFO VALUES (2, '캐드반');
INSERT INTO CLASS_INFO VALUES (3, '디자인반');
INSERT INTO STUDENT_INFO VALUES (1, '김자바', 20, 1);
INSERT INTO STUDENT_INFO VALUES (2, '이자바', 30, 1);
INSERT INTO STUDENT_INFO VALUES (3, '박자바', 40, 1);
INSERT INTO STUDENT_INFO VALUES (4, '최자바', 50, 1);
INSERT INTO STUDENT_INFO VALUES (5, '정자바', 60, 1);
INSERT INTO STUDENT_INFO VALUES (6, '김길동', 15, 2);
INSERT INTO STUDENT_INFO VALUES (7, '이길동', 25, 2);
INSERT INTO STUDENT_INFO VALUES (8, '박길동', 35, 2);
INSERT INTO STUDENT_INFO VALUES (9, '최길동', 45, 2);
INSERT INTO STUDENT_INFO VALUES (10, '정길동', 55, 2);
INSERT INTO STUDENT_INFO VALUES (11, '김유신', 13, 3);
INSERT INTO STUDENT_INFO VALUES (12, '이유신', 23, 3);
INSERT INTO STUDENT_INFO VALUES (13, '박유신', 33, 3);
INSERT INTO STUDENT_INFO VALUES (14, '최유신', 43, 3);
INSERT INTO STUDENT_INFO VALUES (15, '정유신', 53, 3);
COMMIT;
두 테이블을 이용해 조인하여 필요항목을 조회하도록 한다.
그래서 학생정보테이블에는 학급명이 없어서 resultMap에 별도로 추가하는 대신 원래없던 학생정보StuVO에 학급명className 변수를 선언해야한다!
<?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="stuMapper">
<resultMap type="kh.study.ajax.vo.ClassVO" id="classInfo">
<id column="CLASS_CODE" property="classCode"/>
<result column="CLASS_NAME" property="className"/>
</resultMap>
<resultMap type="kh.study.ajax.vo.StuVO" id="stuInfo">
<id column="STU_NUM" property="stuNum"/>
<result column="STU_NAME" property="stuName"/>
<result column="STU_AGE" property="stuAge"/>
<result column="CLASS_CODE" property="classCode"/>
<result column="CLASS_NAME" property="className"/>
</resultMap>
<!-- 학급목록조회 -->
<select id="getClassList" resultMap="classInfo">
SELECT CLASS_CODE
,CLASS_NAME
FROM CLASS_INFO
ORDER BY CLASS_CODE
</select>
<!-- 학생목록조회 (조인 ver.) -->
<select id="getStuList" resultMap="stuInfo">
SELECT STU_NUM
, STU_NAME
, STU_AGE
, CLASS_NAME
FROM CLASS_INFO C,STUDENT_INFO S
WHERE C.CLASS_CODE = S.CLASS_CODE
ORDER BY STU_NUM
</select>
</mapper>
만약 서브쿼리이용해서 학생목록조회한다면 아래 코드 사용
- 학생목록조회 (서브쿼리 ver.)
<select id=""> SELECT STU_NUM , STU_NAME , STU_AGE , (SELECT CLASS_NAME FROM CLASS_INFO WHERE CLASS_CODE = S.CLASS_CODE) FROM STUDENT_INFO S ORDER BY STU_NUM </select>
(각 테이블 해당 VO파일 생성)
package kh.study.ajax.vo;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class ClassVO {
private int classCode;
private String className;
}
package kh.study.ajax.vo;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class ScoreVO {
private int scoreNum;
private int korScore;
private int engScore;
private int mathScore;
private int stuNum;
}
Mapper에서 resultMap 컬럼에 별도로 추가했으면 StuVO에도 추가해야한다.
private String className;
package kh.study.ajax.vo;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class StuVO {
private int stuNum;
private String stuName;
private int stuAge;
private int classCode;
//resultMap에 추가했으면 VO에도 추가
private String className;
}
package kh.study.ajax.service;
import java.util.List;
import kh.study.ajax.vo.ClassVO;
import kh.study.ajax.vo.StuVO;
public interface StuService {
//학급목록 조회
List<StuVO> getStuList();
List<ClassVO> getClassList();
}
package kh.study.ajax.service;
import java.util.List;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import kh.study.ajax.vo.ClassVO;
import kh.study.ajax.vo.StuVO;
@Service("stuService")//컨트롤러연결
public class StuServiceImpl implements StuService {
@Autowired//어노테이션으로 객체생성
private SqlSessionTemplate sqlSession;
//학급목록조회
@Override
public List<ClassVO> getClassList() {
return sqlSession.selectList("stuMapper.getClassList");
}
//학생목록조회
@Override
public List<StuVO> getStuList() {
return sqlSession.selectList("stuMapper.getStuList");
}
}
우선 ajax 사용안하고 html로 페이지이동!
package kh.study.ajax.controller;
import javax.annotation.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import kh.study.ajax.service.StuService;
import kh.study.ajax.vo.ClassVO;
import kh.study.ajax.vo.StuVO;
@Controller
@RequestMapping("/stu")
public class StuController {
//service 객체를 만들어줘야 안에 메소드사용가능!
@Resource(name = "stuService")//@Service("/stuService") 인터페이스와 연결
private StuService stuService;
@RequestMapping("/list")
public String selectStuList(Model model,StuVO stuVO, ClassVO classVO) {
model.addAttribute("classList",stuService.getClassList());
model.addAttribute("stuList",stuService.getStuList());
return "stu_manage";//페이지이동
}
}
타임리프_리스트데이터 뽑는 방법
- 중요 point! 테이블 1열 2행을 구현하여 한화면에 양면분할로 만들어준다 -> css 중요
- 컨트롤러에서 보낸 classList,stuList라는 이름으로 던져진 데이터를 받아서 classInfo,stuInfo라는 이름을 사용해 foreach문 타임리프를 이용해 각각의 리스트에서 하나씩 빼서 목록조회한다.
th:each="classInfo : ${classList}"
- 타임리프 text를 사용하면 실제로 데이터를 화면에 보이게 할 수 있다.
th:text="${classInfo.className}"
- 단, 코드에서처럼 학급명은 기본키인 학급코드로 value값으로 데이터를 받아야한다!(내부적)
th:value="${classInfo.classCode}"></option>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
.layoutTable{
width: 1000px;
margin: 0 auto;
border: 1px solid black;
border-collapse: collapse;
margin-top: 40px;
text-align: center;
}
.layoutTable > tbody >tr, .layoutTable > tbody > tr >td{
border: 1px solid black;
}
.layoutTable > tbody> tr{/* 자식 */
height: 500px;
}
.layoutTable > tbody> tr > td{/* 자식 */
vertical-align: top;
padding: 20px;
}
.stuListTable{
width: 400px;
border: 1px solid gray;
border-collapse: collapse;
margin: 0 auto;
}
.stuListTable tr,.stuListTable td{/* 자손 */
border: 1px solid gray;
}
</style>
</head>
<body>
<table class="layoutTable">
<colgroup>
<col width="50%">
<col width="50%">
</colgroup>
<tr>
<td>
<div style="margin-bottom: 10px;" align="center">
<select>
<option>전체</option>
<option th:each="classInfo : ${classList}" th:text="${classInfo.className}" th:value="${classInfo.classCode}"></option>
</select>
</div>
<div>
<table class="stuListTable">
<thead>
<tr>
<td>학번</td>
<td>이름</td>
<td>나이</td>
<td>학급명</td>
</tr>
</thead>
<tbody>
<th:block th:each="stuInfo : ${stuList}" >
<tr>
<td th:text="${stuInfo.stuNum}" ></td>
<td th:text="${stuInfo.stuName}" ></td>
<td th:text="${stuInfo.stuAge}" ></td>
<td th:text="${stuInfo.ClassName}" ></td>
</tr>
</th:block>
</tbody>
</table>
</div>
</td>
<td></td>
</tr>
</table>
</body>
</html>