[Kakao API] 개인정보 수정 + Oracle TRIGGER

2025. 4. 11. 18:30·Web

쿠폰 테이블, 트리거

/*
[포인트 테이블 생성시 고려할 점]
기획자 => COUPON => 할인율 or 포인트 or 적립금 => 컬럼 필요
1. 할인율, 포인트 기능
2. 쿠폰을 사용할 수 있는 날짜 제한 
3. 해당 쿠폰을 사용할 수 있는 상품 설정  
*/

create table COUPON(
MIDX NUMBER(3) NOT NULL,
COUPON_NM NVARCHAR2(50) NOT NULL,
COUPON_POINT NUMBER(6) NOT NULL,
COUPON_DATE TIMESTAMP DEFAULT SYSDATE
)


/*
트리거는 테이블 생성후 생성
IDE에서 트리거 생성시 오류 발생함
SQL developer에서 트리거 만들어야함 
*/

-- 아래 테이블 SQL developer에서 실행 후 커밋해서 실제테이블에 적용하기 
CREATE OR REPLACE TRIGGER CP
AFTER INSERT ON MEMBERSHIP
FOR EACH ROW
BEGIN
INSERT INTO COUPON (MIDX,COUPON_NM,COUPON_POINT,COUPON_DATE)
VALUES (:NEW.MIDX,'신규회원가입 쿠폰',1000,SYSDATE);
END;

-- 트리거 정지 
ALTER TRIGGER CP DISABLE; 

-- 트리거 재실행
ALTER TRIGGER CP ENABLE; 

-- drop trigger cp;		-- 트리거 삭제 

-- 트리거 조회 
SELECT TRIGGER_NAME FROM USER_TRIGGERS WHERE TABLE_NAME ='MEMBERSHIP';

-- 쿠폰 조회 
SELECT * FROM COUPON;

/*
Oracle Table JOIN시 주의점 on사용후 where 적용하기 
1. JOIN ON WHERE
2. JOIN ON
3. JOIN , WHERE
*/
-- 조인해서 검색하기 ON
SELECT A.MIDX, A.MCODE, A.MID, A.MNAME, A.MEMAIL, B.COUPON_NM
FROM MEMBERSHIP A JOIN COUPON B ON A.MIDX = B.MIDX 
WHERE A.MIDX='39';

-- 조인해서 검색하기 WHERE
-- 조인시 where을 바로 사용해야 할 경우 테이블과 테이블 사이에 콤마, 를 사용해 핸들링 
SELECT A.MIDX, A.MCODE, A.MID, A.MNAME, A.MEMAIL, B.COUPON_NM
FROM MEMBERSHIP A, COUPON B WHERE A.MIDX = B.MIDX;

-- 뷰 생성 위 쿼리를 이용 
CREATE VIEW USER_INFO AS SELECT A.MIDX, A.MCODE, A.MID, A.MNAME, A.MEMAIL, B.COUPON_NM
FROM MEMBERSHIP A, COUPON B WHERE A.MIDX = B.MIDX;

SELECT * FROM USER_INFO;	-- 검색 

DROP VIEW USER_INFO;	-- 삭제

 

kakao2.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인및 외부 API 로그인 방식(Kakao)</title>
</head>
<body>

	<form id="frm" method="post" action="./ajax/web_loginok.do">
	<!-- code = 1일반로그인 2카카오로그인 -->
		<input type="hidden" name="code" value="1">
		<input type="hidden" name="kakao_id" value="">
		<input type="hidden" name="kakao_nicknm" value="">
		<!-- autocomplete 자동완성 해제 : 보안굿 -->
		 아이디 : <input type="text" name="mid" autocomplete="off"><br> 
		 패스워드 : <input type="password" name="mpass"><br> 
		 <input type="submit" value="로그인"><br>
		 <input type="checkbox" id="save_id">아이디 저장<br>
		 <!-- 
		 자동로그인 기능은 실제로그인이 한번 돼야 활성화됨
		 자동로그인은 Back-end가 세션스토리지가 아니라 로컬스토리지로 셋아이템으로 브라우저에 저장해야함 
		 아이디 저장은 Front-end가 로컬스토리지에 저장함		 
		 -->
	</form>
	
	<br>
	<br>
	<img src="./ajax/kakao_login.png" onclick="kakao_login()">
	<p id="token-result"></p>
</body>
<script src="https://t1.kakaocdn.net/kakao_js_sdk/v1/kakao.js"></script>
<script>
	Kakao.init('키');
	function kakao_login() {
		// Kakao.Auth.login : 카카오 회원가입 및 로그인 페이지를 출력하는 함수 
		Kakao.Auth.login({
			//성공시 출력되는 형태 
			success : function(response) {	//response : 결과화면 (사실 여기서 안넣어도됨)
				Kakao.API.request({			//사용자 가입정보를 요청 
					url : '/v2/user/me',	// 사용자 정보 가져오기
					success : function(response) {	//API서버에서 가입정보를 가져옴 
						console.log(response);
						let id = response["id"];		//고유값 
						let nickname = response["kakao_account"]["profile"]["nickname"];		//카카오 닉네임
						frm.code.value = "2";
						frm.kakao_id.value = id;
						frm.kakao_nicknm.value = nickname;
						frm.submit();
					},
					fail : function(error) {
						console.log(error);
						console.log("카카오 API 접속 오류");
					}
				});
			},
			//API 키가 맞지 않을 경우 출력되는 함수 
			fail : function(error) {
				console.log(error);
				console.log("카카오 key 접속 오류 및 환경설정 오류");
			}
		});
	}
</script>
<script>
	
</script>
<script>
	//해당 페이지로 접속시 작동되는 함수 
	window.onload = function(){
		let userid = localStorage.getItem("userid");
		if(userid != null){	//아이디 저장기능 활성화 
			frm.mid.value = userid;
			document.querySelector("#save_id").checked = true;	//아이디 저장 체크박스 체크 
		}
	}

	//아이디 저장 
	document.querySelector("#save_id").addEventListener("click", function(e) {
		if(frm.mid.value == ""){	
			alert("아이디를 입력하셔야 해당 기능을 사용할 수 있습니다.");
			this.checked = false;	//체크안되게 만들기 
		}else{
			if(this.checked == true){
				localStorage.setItem("userid",frm.mid.value);
			}else{
				localStorage.clear();
			}
			
		}
	});

	// ECMA => submit 사용 시 return, return false가 없습니다.
	document.querySelector("#frm").addEventListener("submit", function(e) {
		e.preventDefault(); // 강제정지
		if (frm.mid.value == "") {
			alert("아이디를 입력하세요");
		} else if (frm.mpass.value == "") {
			alert("패스워드를 입력하세요");
		} else {
			frm.submit();
		}
	});
</script>
</html>

 

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="mytld.mycompany.myapp.membership_mapper">

<!-- 
map 이용하여 하나의 쿼리문으로 조건에 맞는 sql이 작동 되도록 설정
 -->
<select id="id_info" resultType="membership_DTO" parameterType="Map">
select mid,mpass,mhp,memail from membership
<choose>
 	<when test="part == 'login'"> <!-- 로그인 -->
 	 <where> <!-- where 태그는 where절을 입력시키는 태그 -->
 	 	mid= #{mid} and mpass= #{mpass}
 	 </where>
 	</when>
 	<when test="part == 'myinfo'"> <!-- 자신의 정보확인 및 수정 (kakao) -->
 	 	where mid= #{mid}
 	</when>
 	<otherwise> <!-- 회원전체 리스트 -->
 		order by midx desc
 	</otherwise>
</choose>

</select>

<select id="id_row" resultType="String">
select count(*) as ctl from membership where mid=#{mid}
</select>

<insert id="join_insert">
insert into membership (MIDX,MCODE,MID,MNAME,MNICK,MPASS,MEMAIL,MHP,MJOIN,MDATE) 
values (MNO.NEXTVAL,#{MCODE},#{MID},#{MNAME},#{MNICK},#{MPASS},#{MEMAIL},#{MHP},#{MJOIN},SYSDATE)
</insert>

 
<update id="id_update" parameterType="Map">
update membership set 
<choose>
<when test="MPASS != null">		<!-- MPASS의 값이 있을 경우 -->
MPASS = #{MPASS}, MHP = #{MHP}, MEMAIL = #{MEMAIL} 
</when>
<otherwise>		<!-- MPASS의 값이 없을 경우 -->
MHP = #{MHP}, MEMAIL = #{MEMAIL} 
</otherwise>
</choose>
where MID=#{MID}
</update>

</mapper>

 

membership_mapper.java

package mytld.mycompany.myapp;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface membership_mapper {
	public String id_row(String mid);
	public int join_insert(membership_DTO dto);
	public List<membership_DTO> id_info(String mid, String mpass);
	public int id_update(Map<String,String> map);	//개인정보 수정 
}

membership_DAO.java

package mytld.mycompany.myapp;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;

@Repository("membership_DAO")
public class membership_DAO implements membership_mapper {

	@Resource(name="sqltemp")
	public SqlSessionTemplate st;
	
	Map<String, String> mp = null;
	private static final Logger logger = LoggerFactory.getLogger(membership_DAO.class);
	@Override
	public List<membership_DTO> id_info(String mid, String mpass) {
		//Map 생성하는 이유 : mapper.xml에서 choose을 사용하여 각 when(조건) 별로 query를 다르게 실행 시키기 위함
		this.mp = new HashMap<String, String>();
		if(mpass != "") {
			this.mp.put("part", "login");
			this.mp.put("mid", mid);
			this.mp.put("mpass", mpass);
		}
		else {
			this.mp.put("part", "myinfo");
			this.mp.put("mid", mid);
		}
		//해당 조건에 mapper값을 return받음
		List<membership_DTO> all = this.st.selectList("id_info",this.mp);
		return all;
	}
	
	@Override
	public String id_row(String mid) {
		String result = null;
		try {
			//id는 대문자 소문자를 구분한다.
			result = st.selectOne("id_row",mid);
		}catch (Exception e) {
			System.out.println(e);
		}
		return result;
	}
	
	
	@Override
	public int join_insert(membership_DTO dto) {
		int result = 0;
		result = st.insert("join_insert",dto);
		return result;
	}
	
	
	@Override
	public int id_update(Map<String, String> map) {
		int result = this.st.update("id_update",map);
		return result;
	}
}

 

controller.java

package mytld.mycompany.myapp;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.dbcp.BasicDataSource;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttribute;

@Controller
public class HomeController {

	private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

	@Autowired
	BasicDataSource dbinfo;

	@Resource(name = "membership_DAO")
	membership_DAO dao;

	@Resource(name = "m_md5")
	m_md5 md5 = null;

	HttpSession session = null;

	PrintWriter pw = null;

	String msg = null;

	// kakao2.jsp에서 넘어옴
	// @Post도 받고 @Get도 받아야됨
	// @Post => 일반로그인, kakao api, @Get => kakao Script
	// 일반로그인 + Kakao Script Login => @RequestMapping
	// 일반로그인 + Kakao API => @PostMapping
	/*
	 * ServletRequest, ServletResponse => session 사용 불가능 HttpServletRequest,
	 * HttpServletResponse => session 사용가능
	 */
	@RequestMapping("/ajax/web_loginok.do")
	public String web_loginok( // DTO로 받아도됨
			@RequestParam(name = "code") String code, @RequestParam(name = "mid", required = false) String mid,
			@RequestParam(name = "mpass", required = false) String mpass,
			@RequestParam(name = "kakao_id", required = false) String kakao_id,
			@RequestParam(name = "kakao_nicknm", required = false) String kakao_nicknm, Model m,
			HttpServletRequest req) {
		
		this.session = req.getSession();

		if (code.equals("1")) { // 일반 로그인 처리

			String pw = this.md5.md5_pass(mpass); // 사용자가 입력한 값을 암호화하여 회신
			List<membership_DTO> all = this.dao.id_info(mid, pw);
			System.out.println(all.size());

			if (all.size() > 0) {
				// 해당 로그인시 아이디를 session으로 등록함
				this.session.setAttribute("mid", all.get(0).getMID());

				System.out.println("세션 MID: " + this.session.getAttribute("mid"));

//				this.msg = "alert('로그인하였습니다');location.href='./myinfo.do';";
				this.msg = "setTimeout(function() { alert('로그인하였습니다'); location.href='./myinfo.do'; }, 300);";

				this.logger.info("로그인확인");
			} else {
				this.msg = "alert('로그인 실패하였습니다');" + "history.go(-1);";
				this.logger.info("로그인미확인");
			}
			m.addAttribute("msg", msg);

		} else if (code.equals("2")) { // 카카오 로그인 처리
			List<membership_DTO> all = this.dao.id_info(kakao_id, "");
			if (all.size() > 0) {
				//해당 로그인시 아이디를 session으로 등록함
				this.session.setAttribute("mid", all.get(0).getMID());
				msg = "alert('로그인 하셨습니다.'); location.href='./myinfo.do';";
			} else {
				// sessionStorage를 이용하여 간편회원가입을 등록하려함
				// 단 닉네임일 경우 특수문자를 사용할 수있으므로 생성시 ''로 변수값을 적용하여 처리
				this.msg = "alert('카카오 사용자로 로그인시 간편회원가입이 필요합니다.');"
						+ "sessionStorage.setItem('mid','"+ kakao_id +"');"
						+ "sessionStorage.setItem('mnick','"+ kakao_nicknm +"');"
						+ "location.href='../join.jsp';";
			}
			m.addAttribute("msg", msg);
		}

		return "joinok";
	}

	// 아이디 체크
	@PostMapping("/login_idck.do")
	public String login_idck(@RequestParam(name = "id") String id, ServletResponse res) {
		String result = null;
		try {
//			this.logger.info(id);
			this.pw = res.getWriter();

			// 아이디 대소문자 구별함
			// toUpperCase : 대문자로
			// toLowerCase : 소문자로
			result = this.dao.id_row(id.toLowerCase());
//			this.logger.info(result);
			if (result == null || result.equals("0")) {
				this.pw.write("ok");
			} else {
				this.pw.write("no");
			}

		} catch (Exception e) {
			this.logger.info(e.toString());
		} finally {
			this.pw.close();
		}

		return null;
	}

	@PostMapping("/joinok.do")
	public String joinok(@ModelAttribute membership_DTO dto, Model m) {

		String pw = dto.getMPASS();
		dto.setMPASS(this.md5.md5_pass(pw)); // 암호화 후 setter 사용

		try {
			int result = this.dao.join_insert(dto);
			if (result > 0) {

				m.addAttribute("msg", "alert('정상적으로 회원가입이 완료되었습니다');" + "location.href='./kakao2.jsp';");
			} else {
				m.addAttribute("msg", "alert('회원가입이 완료되지 않았습니다.');" + "history.go(-1);");
			}
		} catch (Exception e) {
			this.logger.info(e.toString());
		}

		return null;
	}

	// 로그인 사용자 정보 출력하는 페이지
	@GetMapping("/ajax/myinfo.do")
	public String myinfo(@SessionAttribute("mid") String MID, Model m) {
		//사용자 정보 가져옴
		List<membership_DTO> mydata = this.dao.id_info(MID, "");
		m.addAttribute("mydata",mydata);
		
		//세션 ID 전송
		//this.logger.info(MID);
		m.addAttribute("MID", MID);

		return "/myinfo";
	}

	// 로그아웃
	@GetMapping("/ajax/logout.do")
	public String logout(HttpServletRequest req, Model m) {
		this.session = req.getSession();
		this.session.invalidate();

		this.msg = "alert('로그아웃 완료'); location.href='../kakao2.jsp';";

		m.addAttribute("msg", this.msg);

		return "joinok";
	}
	
	
	//배열키에 맞춰서 보내달라고 해야함 
	
	//API Patch로 개인정보 수정
	@PatchMapping("/ajax/myinfo_modify.do/{key}")
	public String myinfo_modify(ServletResponse res,
			@PathVariable("key") String key,
			@RequestBody String datainfo) {
		 try {
	         this.pw = res.getWriter();
	         if(key.equals("mykey")) {
	        	 JSONObject jo = new JSONObject(datainfo);	//=> MAP
	        	 
	        	 Map<String,String> userdata = new HashMap<String, String>();
	        	 //System.out.println(jo.keySet());
	        	 
	        	 for(String k : jo.keySet()) {
	        		 if(!jo.get(k).equals("")) {	//값이 비어있지 않을 경우 맵에 추가 
	        			 if(k.equals("MPASS")) {	//패스워드도 넘어온 경우 
	        				 //md5로 암호화해서 맵에 추가 
	        				 userdata.put(k, this.md5.md5_pass(jo.get(k).toString()));
	        			 }else {
	        				 userdata.put(k, jo.getString(k).toString());
	        			 }
	        		 }
	        	 }
	        	
	        	 this.logger.info(datainfo.toString());
	        	 
	        	 int result = this.dao.id_update(userdata);
	        	 if(result > 0) {
	        		 this.pw.write("ok");
	        	 }else {
	        		 this.pw.write("no");
	        	 }
	        	 
	         }
	         else {
	            this.pw.write("key error");
	         }
	      } catch (Exception e) {
	    	  System.out.println(e);
	         this.pw.write("error");
	      }finally {
	         this.pw.close();
	      }

		
		return null;
	}
	
}

myinfo.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="cr" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page import="java.util.Date"%>
<%Date date = new Date();%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원정보</title>
</head>
<!-- a 태그에 javascript 함수를 호출 시 javascript: 단어를 입력 후 호출 -->
<body>

${sessionScope.mid}님 환영합니다. <a href="javascript:kakao_logout()">[로그아웃]</a>
<br><br><br>

<!-- SPA?형태로 제작 : 어디로 이동 안하고 ajax를 이용 -->

<input type="hidden" id="MID" value="${mydata.get(0).MID}"><br>
이름 : ${mydata.get(0).MID}<br>

<!-- 패스워드에 절대 값 때리면 안됨 
굳이 때리고 싶으면 값 때려도  ******로 그냥 때리기 
암호화해도 시간만 이쓰면 뚫음 개발자도구에서 password 대신 text로 때리면 다보임 -->
패스워드 : <input type="password" id="MPASS"><br>

<!-- 
주의 : disabled된 애는 핸들링이 안됨 말그대로 사용하지 않겠다는 뜻 
Backend로도 안가고 Javascript에서도 핸들링이 불가능함!!!!
풀고싶다면 버튼을 이용해서 인풋의 속성 disabled를 false로 해주기 
 -->
연락처 : <input type="text" id="MHP" value="${mydata.get(0).MHP}" maxlength="11" disabled>
<input type="button" value="연락처수정" id="hpmodify"><br>

<!-- 실무에선 연락처에 나이스 인증 붙어있음 -->
이메일 : <input type="text" id="MEMAIL" value="${mydata.get(0).MEMAIL}" disabled>
<input type="button" value="이메일수정" id="mailmodify"><br>

<input type="button" value="개인정보수정" id="modify_myinfo">


</body>
<script src="../myinfo.js?v=<%=date%>"></script>

<script src="https://t1.kakaocdn.net/kakao_js_sdk/v1/kakao.js"></script>
<script>
Kakao.init('키');	//키발급된 번호
function kakao_logout(){
	if(!Kakao.Auth.getAccessToken()){
		location.href = './logout.do';
	}
	else{
		Kakao.Auth.setAccessToken(undefined);
		sessionStorage.clear();
		localStorage.clear();
		location.href = './logout.do';
	}
}
</script>
</html>

myinfo.js

//disabled된 애는 핸들링이 안됨 
//Backend로도 안가고 Javascript에서도 핸들링이 불가능함!!!!

document.querySelector("#hpmodify").addEventListener("click",function(){
	//해당 연락처 수정 버튼을 클릭시 연락처 입력부분을 수정할 수 있도록 disable 정지시킴
	if(confirm("연락처를 수정하시겠습니까?")){
		document.querySelector("#MHP").disabled = false;
	}
});

//이메일 수정시 적용되는 이벤트 핸들링 함수 
document.querySelector("#mailmodify").addEventListener("click",function(){
	if(confirm("이메일을 수정하시겠습니까?")){
		document.querySelector("#MEMAIL").disabled = false;
	}
});

//배열키 : MPASS, MEMAIL, MHP 이거로 보내주세영 - Back-end
//개인정보수정 버튼 클릭시 AJAX 발동 
document.querySelector("#modify_myinfo").addEventListener("click",function(){
	/*
	//Map 배열로 키를 생성하여 전달하는 방식
	//이거는 Spring에서 전송 안됨! Spring-boot에서는 가능 
	let udata = new Map();
	
	udata.set("MID",document.querySelector("#MID").value);
	//값이 null이면 에러나기때문에 핸들링 필요 
	if(document.querySelector("#MPASS").value != ""){
		udata.set("MPASS",document.querySelector("#MPASS").value);
	}
	udata.set("MHP",document.querySelector("#MHP").value);
	udata.set("MEMAIL",document.querySelector("#MEMAIL").value);
	console.log(udata);
	*/ 
	fetch("./myinfo_modify.do/mykey",{
		method : "PATCH",
		//headers : {"content-type":"application/json"},
		body : JSON.stringify({
			"MID" : document.querySelector("#MID").value,
			"MPASS" : document.querySelector("#MPASS").value,
			"MHP" : document.querySelector("#MHP").value,
			"MEMAIL" : document.querySelector("#MEMAIL").value
		})
		
	}).then(function(result){
		return result.text();
	}).then(function(data){
		 if(data=="ok"){
			alert("정상적으로 변경 완료");
			location.reload();
		}else{
			alert("정보 수정 실패");
			
		}
		console.log(data);
	}).catch(function(error){
		console.log(error);
	});
});
저작자표시 비영리 변경금지 (새창열림)
'Web' 카테고리의 다른 글
  • [Spring-boot] CDN Server 연결
  • 부트스트랩, 닷홈, 파일질라
  • [Kakao API] 회원가입 로그인
  • [Kakao API] 로그인 기초
9na0
9na0
응애
  • 9na0
    구나딩
    9na0
  • 전체
    오늘
    어제
    • 분류 전체보기 (211)
      • Web (118)
      • Java (28)
      • 데이터베이스 (14)
      • 세팅 (12)
      • 과제 (3)
      • 쪽지시험 (2)
      • 정보처리기사 (4)
      • 서버 (25)
  • 블로그 메뉴

    • 링크

      • 포폴
      • 구깃
    • 공지사항

    • 인기 글

    • 태그

      macbook pro m4
      net1
      exam1_1~10
      re2
      re_java10
      file24
      file25
      datalist
      spring-boot
      ab1
      io_dto
      net3
      Oracle
      net4
      noticewriteok
      notice_writer
      file25_t
      net2
      net5~10
      java_io1~10
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.3
    9na0
    [Kakao API] 개인정보 수정 + Oracle TRIGGER
    상단으로

    티스토리툴바