[Spring 에서 CRUD]
1. 뷰에서 컨트롤러로 action 전달
2. 컨트롤러에 빈 메소드 추가 후 테스트
3. mapper.xml에 쿼리문 추가
4. 쿼리문 id복사
5. mapper.java 인터페이스에 추가
6. DAO에 추가
7. 컨트롤러에서 사용
macbook.html
강의 개설하는 view
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>과정 개설</title>
</head>
<body>
<script src="./macbook.js?v=1"></script>
<form id="frm" method="post" action="./macbook_ok.do">
과정구분 :
<select name="class_part">
<option value="온라인 상시과정">온라인 상시과정</option>
<option value="온라인 정규 과정">온라인 정규 과정</option>
<option value="집합 과정">집합 과정</option>
</select><br>
과정 카테고리 :
<select name="class_cate">
<option value="교육">교육</option>
<option value="보강">보강</option>
<option value="자격증">자격증</option>
</select><br>
과정명 : <input type="text" name="class_name"><br>
학습일수 : <input type="text" name="class_day"><br>
정가 : <input type="text" name="class_price"><br>
수강료 : <input type="text" name="class_sales"><br>
과정소개 : <textarea cols="100" rows="5" name="class_info"></textarea><br>
강사명 : <input type="text" name="class_teacher"><br>
학습목표 : <textarea cols="100" rows="5" name="class_object"></textarea><br>
강의 개강 여부 : <input type="radio" value="Y" name="class_use">개강
<input type="radio" value="N" name="class_use" checked>종강<br>
<input type="button" value="강의개설" onclick="save_class()">
</form>
</body>
</html>
macbook.java (Controller)
컨트롤러 : 강의 리스트 출력, 강의 생성, 강의 수정, 강의 삭제
package spring_learning;
import java.io.PrintWriter;
import java.util.List;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class macbook {
// 컨트롤러의 리소스 네임과 DAO의 레포지토리 이름이 같으면 됨 !
// @Resource : new 클래스명 호출과 동일하게 작동, @Repository의 이름을 가져오는 역할
// @Resource와 @Repository는 영혼의 단짝친구
@Resource(name = "macbook_DAO") // resource는 new의 역할
private macbook_DAO dao; // 하나의 모델인데 new 안써도 됨
// 그럼 이렇게 DTO를 쓰면 this.를 이용해서 DTO를 사용 가능하게됨 !
// 대신 매개변수와 변수 이름이 같으면 에러가 날 수도 있음 주의 !!
@Resource(name = "macbook_DTO")
private macbook_DTO mdto;
// 과정 리스트 출력
@GetMapping("/macbook_list.do")
public String macbook_list(Model m) {
// List<macbook_DTO> : DTO 형태의 배열로 생성하여, JSP로 전달
List<macbook_DTO> classList = this.dao.macbook_select();
System.out.println(classList.get(0).class_name);
m.addAttribute("ea", classList.size());
m.addAttribute("classList", classList);
return null;
}
// 과정개설 메소드
@PostMapping("/macbook_ok.do")
public String macbook_ok(macbook_DTO dto, Model m) throws Exception {
try {
// dao : 쿼리문을 작동시키는 놈
int result = this.dao.macbook_insert(dto);
String msg = "";
if (result > 0) {
msg = "alert('과정이 올바르게 개설되었습니다.');" + "location.href='macbook_list.do';";
}
m.addAttribute("msg", msg);
} catch (Exception e) {
}
return "load";
}
// 수정 페이지 출력
@PostMapping("/macbook_modify.do")
public String macbook_modify(@RequestParam("midx") String midx, Model m) {
// @RequestParam("midx") => 둘의 이름이 같으면 생략가능 가끔 값이 안받아지면 쓰기
// 단, 체크박스로 배열을 받을때는 리퀘스트 바디, 어트리뷰트 사용
// @RequestParam("midx") : front의 midx를
// String midx : 매개변수명을 이거로 받겠음! (아무거나 써도됨)
// macbook_DTO의 setter에 값을 이관한 상황
macbook_DTO onedata = this.dao.macbook_one(midx);
// System.out.println(onedata.class_name); // DTO의 getter 메소드를 사용
m.addAttribute("onedata", onedata); // JSTL로 값을 이관함
return null;
}
// 과정을 수정하는 메소드
@PostMapping("/macbook_modifyok.do")
public String macbook_modifyok(macbook_DTO dto, Model m) {
int result = this.dao.macbook_update(dto); // DAO로 값을 전송
// System.out.println(result);
String msg = "";
if (result > 0) {
msg = "alert('정상적으로 데이터가 수정되었습니다.');" + "location.href='./macbook_list.do';";
} else {
msg = "alert('error');" + "history.go(-1);";
}
m.addAttribute("msg", msg);
return "load";
}
PrintWriter pw = null;
/*
Model과 HttpServletResponse는 함께 사용 불가
두개의 인터페이스 역할이 같으므로 하나만 사용이 가능
*/
// 개설된 과정을 삭제하는 메소드
@PostMapping("/macbook_delete.do")
//Model과 HttpServletResponse는 상극 => 둘중하나만 쓰기 res쓰면 해당페이지에 출력해서 다음 페이지로 안넘어감 / 모델쓰면 다음페이지에 출력
public String macbook_delete(@RequestParam("midx") String midx, HttpServletResponse res) throws Exception {
res.setContentType("text/html; charset=utf-8");
this.pw = res.getWriter();
int result = this.dao.macbook_delete(Integer.parseInt(midx)); //트캐 필요하긴함
if(result > 0) {
this.pw.print("<script>"
+ "alert('올바르게 해당 과정을 삭제하였습니다');"
+ "location.href='./macbook_list.do';"
+ "</script>");
}
pw.close();
return null;
}
}
- xml정보 끌고오는 애들 Autowired, Inject
- @Autowired @Inject : 의존성 주입 XML=>Java, Java=>XML
- @Autowired SqlSessionFactory sqlfact;
- ibatis로 연결
- @Inject SqlSessionFactory sqlfact;
src/main/resource/META-INF/mapper.xml
사용할 쿼리문을 작성하는 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="spring_learning.macbook_mapper">
<!-- 과정 insert -->
<insert id="macbook_insert">
insert into macbook_class (midx,class_part,class_cate,class_name,class_day,class_price,class_sales,class_info,class_teacher,class_object,class_use,today)
values ('0',#{class_part},#{class_cate},#{class_name},#{class_day},#{class_price},#{class_sales},#{class_info},#{class_teacher},#{class_object},#{class_use},now())
</insert>
<!-- 과정 하나의 데이터 -->
<select id="macbook_one" resultType="macbookdto" parameterType="String"> <!-- id로 받은 데이터 저장하는게 resultType -->
select * from macbook_class where midx=#{midx}
</select>
<!-- 과정 전체의 리스트 데이터 -->
<!-- resultType : config.xml에서 셋팅된 alias를 이용하여 Model DTO에 이관 -->
<select id="macbook_select" resultType="macbookdto">
select * from macbook_class order by midx desc
</select>
<!-- 과정 데이터 수정 -->
<update id="macbook_update">
update macbook_class set class_part=#{class_part}, class_cate=#{class_cate},
class_name=#{class_name }, class_day=#{class_day }, class_price=#{ class_price},
class_sales=#{class_sales }, class_info=#{class_info }, class_teacher=#{class_teacher },
class_object=#{class_object }, class_use=#{class_use }
where midx=#{midx}
</update>
<!-- 과정 데이터 삭제 (자료형 int로 처리)-->
<delete id="macbook_delete" parameterType="int">
delete from macbook_class where midx=#{midx}
</delete>
</mapper>
- SQL 문법에 대한 파일 (mapper)
- namespace="spring_learning.koo"
- spring_learning => 패키지명
- koo 라는 Mapper 어노테이션을 찾음
- => mapper.xml과 koo.java를 연결시켜줌
- namespace="spring_learning.koo"
- DML만 가능 (DDL, DCL 불가능 => 옛날처럼 커넥션으로 만드는 방법 밖에 없음)
- < select>< /select>
- < insert>< /insert>
- < update>< /update>
- < delete>< /delete>
- xml에서는 세미콜론 안씀 !
- ${} : 필드명, 테이블명, 파라미터
- #{} : 값을 적용시킬때 사용하는 파라미터값 => 파라미터에 달러쓰면 보안개스렉이;
- 좋은 예) 외따옴표가 필요없는 애는 달러 / 외따옴표가 필요한 애는 샵
- select * from ${mrp} where mid=#{mid};
- 과정 하나의 데이터 select
- 매개변수 여러개 못받음
- => 매개변수가 여러개일때는 배열이나 맵 하나로 받기!
- resultType을 쓸 수 있는 태그는 select밖에 없음 !
src/main/java/패키지/macbook_mapper.java (Mapper Interface)
package spring_learning;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface macbook_mapper {
public macbook_DTO macbook_one(String midx); //하나의 데이터만 가져옴
public int macbook_insert(macbook_DTO dto); //신규 데이터 입력
public List<macbook_DTO> macbook_select(); //전체 데이터
public int macbook_update(macbook_DTO dto); //과정 수정
public int macbook_delete(int midx); //삭제 (숫자로 처리)
}
- @Mapper : mapper.xml에 있는 namespace와 연동, 메소드를 실행시키는 id와 연동 시키는 interface
- ⭐️Mapper.xml에서 사용하는 id기준으로 메소드 이름을 설정
- 인터페이스 안 메소드명은 mapper.xml의 id와 동일 => mapper는 연결고리
- sql 쿼리문을 실행시킬 수 있도록 적용된 interface
- 쿼리문 안에 #{}때문에 dto를 인자로 넣음
- mapper.xml의 sql 쿼리문들을 @Mapper로 연결시켜 아이디로 작동시키는 인터페이스
- 이녀석은 mapper.xml만 연결됨
- mapper.xml 먼저 쿼리문 만들고 그 id를 이용해서 인터페이스에 올리기
macbook_DAO.java
데이터 Access하는 역할
package spring_learning;
import java.util.List;
import javax.annotation.Resource;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.stereotype.Repository;
//DAO : 데이터를 Access를 하는 역할
@Repository("macbook_DAO") // @Repository : Model을 Controller에 호출시킴
public class macbook_DAO implements macbook_mapper {
// implements macbook_mapper
// 쓰고 컨스페로 자동으로 넣으면 짱좋음 기존에쓰던게있으면 @Override만 붙이면 됨
// 맵퍼 인터페이스 로드하여 DAO작성
// mybatis로 db연결
@Resource(name = "template")
public SqlSessionTemplate st;
// 하나의 데이터만 가져오는 메소드
@Override
public macbook_DTO macbook_one(String midx) {
// setter형태로 DB에 있는 데이터를 이관
// selectOne("mapper.xml 의 id", 매개변수)
macbook_DTO onedata = this.st.selectOne("macbook_one", midx); // mapper.xml 의 id
return onedata;
// 하나만 가져오지만 아래 메소드처럼 selectList로 써도됨
}
//과정 생성 메소드
@Override
public int macbook_insert(macbook_DTO dto) {
int result = this.st.insert("macbook_insert", dto); // st. 컨스페 > sqlsesstion template용 선택
return result;
}
// 전체 리스트 출력 메소드
@Override
public List<macbook_DTO> macbook_select() {
// selectOne : 데이터 한개만 가져올 때 (dto, List배열, ArrayList, Map 등등 다 가능)
// selectList : 데이터 여러개를 가져올 때 (List배열로 가져옴)
List<macbook_DTO> classList = this.st.selectList("macbook_select");
return classList;
}
// 데이터 수정 메소드
@Override
public int macbook_update(macbook_DTO dto) {
int result = this.st.update("macbook_update", dto);
return result;
}
// 데이터 삭제 메소드
@Override
public int macbook_delete(int midx) {
int result = this.st.delete("macbook_delete", midx);
return result;
}
}
- DAO : 데이터를 Access를 하는 역할
- @Repository : Model을 Controller에 호출시킴
- Controller에서 @Resource를 이용하여 호출 (new의 역할)
- implements macbook_mapper
- 먼저 만든 Mapper interface를 implements로 구현
- 컨트롤 + 스페이스바 사용하여 오버라이드하기
- mybatis로 db연결
- @Resource(name = "template")
public SqlSessionTemplate st;
- @Resource(name = "template")
- DAO 작성 후 Controller에서 해당 메소드 호출하여 사용
나머지 view들
macbook_list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="cr" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>과정 개설 리스트</title>
</head>
<body>
<p>개설된 과목 갯수 : ${ea }</p>
<!-- DTO에 있는 변수명으로 JSTL로 출력하는 형태 -->
<cr:forEach var="cdata" items="${classList }">
과정명 : ${cdata['class_name']},
강사명 : ${cdata.class_teacher},
수강료 : ${cdata.class_price}
<input type="button" value="수정" onclick="macbook_modify('${cdata.midx}')">
<input type="button" value="삭제" onclick="macbook_del('${cdata.midx}')">
<br>
</cr:forEach>
<!--
POST : 해당 게시물의 고유값을 POST Backend 전송
따로 폼만들어서 보내기
이것도 보안뚫림 : 개발자도구에서 히든값 바꿀수있음
=> innerHtml 만들기
-->
<!--
form으로 post전송
form하나로 함수 두개 사용 => js에서 action값 넣기
-->
<form id="frm" method="post" action="">
<input type="hidden" name="midx" value="">
</form>
<!--
<div id="msg"></div>
-->
</body>
<script>
function macbook_modify(n){
//Post 통신 (form)
frm.midx.value=n;
frm.action="./macbook_modify.do";
frm.submit();
//실무용 POST 전송
//해커가 수정할 틈 없이 전송됨 -> 보안 good
/*
var m = document.getElementById("msg");
m.innerHTML = `<form id="frm" action="./macbook_modify.do">
<input type="hidden" name="midx" value="`+n+`">
</form>`;
frm.submit();
*/
//GET : 빠르지만 눈에 보임
//location.href='./macbook_modify.do?midx='+n;
//데이터를 여러개 붙일 경우 (+'&data='+n1+...); 실수마니생김
//=> 그냥 form 으로 hidden 써서 get으로 넘겨도 됨
}
function macbook_del(n){
if (confirm('해당 과정을 삭제하시겠습니까?\n삭제시 데이터는 복구되지 않습니다.')) {
frm.midx.value = n;
frm.action = "./macbook_delete.do";
frm.submit();
}
}
</script>
</html>
- 고수의 post 전송
macbook_modify.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="cr" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>과정 수정 페이지</title>
</head>
<body>
<script src="./macbook.js?v=1"></script>
<form id="frm" method="post" action="./macbook_modifyok.do">
<!--
수정 또는 삭제시 무조건 고유값 필요
이거 안담으면 안됨 !
-->
<input type="hidden" name="midx" value="${onedata.midx}">
<!-- 1. front에서 js로 찍기 -->
과정구분 :
<select name="class_part">
<option value="온라인 상시과정">온라인 상시과정</option>
<option value="온라인 정규 과정">온라인 정규 과정</option>
<option value="집합 과정">집합 과정</option>
</select><br>
<!--
2. back이 JSTL로 찍기
배열이었다면 forEach 사용
지금은 따로따로 되어있어서 각각 집어넣음
-->
과정 카테고리 :
<select name="class_cate">
<option value="교육"
<cr:if test = "${onedata.class_cate} =='교육'}">selected</cr:if>
>교육</option>
<option value="보강"
<cr:if test = "${onedata.class_cate} =='보강'}">selected</cr:if>
>보강</option>
<option value="자격증"
<cr:if test = "${onedata.class_cate} =='자격증'}">selected</cr:if>
>자격증</option>
</select><br>
<!--
input은 value에
textarea는 태그 사이에
값 찍기
-->
과정명 : <input type="text" name="class_name" value="${onedata.class_name}"><br>
학습일수 : <input type="text" name="class_day" value="${onedata.class_day}"><br>
정가 : <input type="text" name="class_price" value="${onedata.class_price}"><br>
수강료 : <input type="text" name="class_sales" value="${onedata.class_sales}"><br>
과정소개 : <textarea cols="100" rows="5" name="class_info">${onedata.class_info}</textarea><br>
강사명 : <input type="text" name="class_teacher" value="${onedata.class_teacher}"><br>
학습목표 : <textarea cols="100" rows="5" name="class_object">${onedata.class_object}</textarea><br>
<!-- 기존에 태그에 넣어져있던 checked 지우기 -->
강의 개강 여부 :
<input type="radio" value="Y" name="class_use"
<cr:if test = "${onedata.class_use} =='Y'}">checked</cr:if>
>개강
<input type="radio" value="N" name="class_use"
<cr:if test = "${onedata.class_use} =='N'}">checked</cr:if>
>종강<br>
<input type="button" value="강의수정" onclick="save_class()">
</form>
</body>
<script>
//⭐.js 파일에서 Back-end 코드를 사용할 수 없음
window.onload = function(){
//javascript 변수는 backend의 모든 변수값을 받을 수 있음
var subject = "${onedata.class_part}";
//console.log(subject);
var ea = frm.class_part.length;
console.log("ea : "+ea);
console.log("value : "+frm.class_part.value);
for(var f=0; f<ea; f++){
if(frm.class_part[f].value == subject){
frm.class_part[f].selected = "selected"; //체크박스면 checked
}
}
}
</script>
</html>
- 수정 페이지
- select
- js를 이용하여 onload함수에서 반복문으로 처리
- JSTL를 이용하여 배열일때 forEach를 사용해 처리
- checkbox
- jstl로 넘어온 값을 이용하여 if문으로 체크박스 체크 활성화 비활성화
- select
[Front에 script 찍기]
Model과 HttpServletResponse는 함께 사용 불가
두개의 인터페이스 역할이 같으므로 하나만 사용이 가능
PrintWriter : 해당 페이지에 출력 => return에 다음 페이지 써놔도 안넘어감!
Model : 다음 페이지에 전달
1. PrintWriter (HttpServletResponse)
PrintWriter pw = null;
public String macbook_delete(@RequestParam("midx") String midx, HttpServletResponse res) throws Exception {
res.setContentType("text/html; charset=utf-8");
this.pw = res.getWriter();
int result = this.dao.macbook_delete(Integer.parseInt(midx)); //트캐 필요하긴함
if(result > 0) {
this.pw.print("<script>"
+ "alert('올바르게 해당 과정을 삭제하였습니다');"
+ "location.href='./macbook_list.do';"
+ "</script>");
}
pw.close();
return null;
}
2. Model
@PostMapping("/macbook_modifyok.do")
public String macbook_modifyok(macbook_DTO dto, Model m) {
int result = this.dao.macbook_update(dto); // DAO로 값을 전송
String msg = "";
if (result > 0) {
msg = "alert('정상적으로 데이터가 수정되었습니다.');" + "location.href='./macbook_list.do';";
} else {
msg = "alert('error');" + "history.go(-1);";
}
m.addAttribute("msg", msg);
return "load";
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<script>
//Controller에서 Model로 전달된 값을 JSTL 변수 형태로 출력시키는 방식
${msg}
</script>