오늘이라도
[Spring] 4. 웹사이트 만들기 ③ : 회원 신규 등록, 회원 정보 수정, 회원 정보 삭제 본문
취업성공패키지 SW 개발자 교육/Spring
[Spring] 4. 웹사이트 만들기 ③ : 회원 신규 등록, 회원 정보 수정, 회원 정보 삭제
upcake_ 2020. 7. 2. 09:34반응형
https://github.com/upcake/Class_Examples
교육 중에 작성한 예제들은 깃허브에 올려두고 있습니다.
gif 파일은 클릭해서 보는 것이 정확합니다.
- 웹사이트 만들기 ③ : 회원 신규 등록, 회원 정보 수정, 회원 정보 삭제 -
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>new JSP</title>
</head>
<body>
<jsp:include page="/WEB-INF/views/include/header.jsp" />
<div id="content">
<h3>신규 고객</h3>
<form action="insert.cu" method="post">
<table class='w-pct60'>
<tr>
<th class='w-px160'>성명</th>
<td><input type="text" name="name" /></td>
</tr>
<tr>
<th>성별</th>
<td>
<label><input type="radio" name="gender" value="남" checked/>남</label>
<label><input type="radio" name="gender" value="여" />여</label>
</td>
</tr>
<tr>
<th>이메일</th>
<td><input type="text" name="email" /></td>
</tr>
<tr>
<th>전화번호</th>
<td><input type="text" name="phone" /></td>
</tr>
</table>
</form>
<div class="btnSet">
<a class="btn-fill" onclick="$('form').submit()">저장</a>
<a class="btn-empty" href="list.cu">취소</a>
</div>
</div>
<jsp:include page="/WEB-INF/views/include/footer.jsp" />
</body>
</html>
▲new.jsp
@charset "UTF-8";
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR&display=swap');
body {
margin: 0 auto;
text-align: center;
font-size: 16px;
font-family: 'Noto Sans KR', sans-serif;
}
a:link, a:visited {
text-decoration: none;
color: #000;
}
#content {
padding: 20px 0;
min-width: 1024px; /* 창의 최소 크기 지정 */
}
img {
vertical-align: middle; /* 세로축 가운데 정렬 */
}
table {
width: 80%;
margin: 0 auto;
border: 1px solid;
border-collapse: collapse; /* 테두리 겹침 설정 collapse: 겹치지 않게 처리 */
}
table th, table td {
border: 1px solid;
padding: 5px 10px;
}
table td a:hover { font-weight: bold; }
.btnSet { margin-top: 20px; }
a.btn-fill, a.btn-empty {
text-align: center;
padding: 3px 10px;
border:1px solid #3367d6;
border-radius: 3px;
box-shadow: 2px 2px 3px #022d72;
/* 오른쪽, 아래쪽, 번진 정도 */
}
a.btn-fill {
background-color: #3367d6;
color: #fff;
}
a.btn-empty {
background-color: #fff;
color: #3367d6
}
.btnSet a:not(:first-child) {
margin-left: 3px;
}
a:hover { cursor:pointer; }
input {
height: 22px;
padding: 3px 5px;
font-size: 15px;
}
input[type=radio] {
width: 18px;
margin: 0 5px 3px;
vertical-align: middle;
}
table tr td label:not(:last-child) {
margin-right: 20px;
}
.w-pct60 { width: 60% }
.w-pct70 { width: 70% }
.w-pct80 { width: 80% }
.w-px40 { width: 40px }
.w-px60 { width: 60px }
.w-px80 { width: 80px }
.w-px100 { width: 100px }
.w-px120 { width: 120px }
.w-px140 { width: 140px }
.w-px160 { width: 160px }
.w-px180 { width: 180px }
.w-px200 { width: 200px }
▲common.css
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="core" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>list JSP</title>
</head>
<body>
<jsp:include page="/WEB-INF/views/include/header.jsp"></jsp:include>
<div id="content">
<h3>고객 목록</h3>
<!-- CSS 파일을 변경 후에 바로 Refresh가 안된다면 common.css 파일로 들어가서 바로 Refresh 해주면 적용 된다. -->
<table class='w-pct60'>
<tr>
<th class='w-px60'>번호</th>
<th class='w-px200'>고객명</th>
<th>전화번호</th>
</tr>
<!-- for(꺼낸 배열 변수를 담을 새로운 변수 (String x) : 배열 변수(list)) -->
<!-- items : 배열 변수 -->
<!-- var : 꺼낸 배열 변수를 담을 새로운 변수 -->
<core:forEach items="${list }" var="vo">
<tr>
<td>${vo.no }</td>
<td><a href='detail.cu?id=${vo.id}'>${vo.name }</a></td>
<td>${vo.phone }</td>
</tr>
</core:forEach>
</table>
<div class="btnSet">
<a class="btn-fill" href="new.cu">신규 고객</a>
</div>
</div>
<jsp:include page="/WEB-INF/views/include/footer.jsp"></jsp:include>
</body>
</html>
▲list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="core" uri="http://java.sun.com/jsp/jstl/core" %>
<!-- 스프링은 따로 라이브러리를 설치하지 않아도 다운 받을 라이브러리를 설정할 수 있다. -->
<!-- 그 중에 jstl 라이브러리도 있기 때문에 사용할 수 있는것 -->
<!-- 라이브러리 목록은 iot/pom.xml, c:\사용자\.m2에서 확인가능 -->
<link rel="stylesheet" type="text/css" href="css/common.css?v=<%=new java.util.Date().getTime() %>">
<!-- rel : 형태는 스타일 시트, 타입은 텍스트로된 css -->
<!-- 주소 뒤에 ?v=로 버전관리를 할 수 있다 -->
<!-- Date()가 임포트가 안될경우 패키지명을 직접 지정해도 된다. -->
<!-- 어느 페이지에 가도 인클루드 되어있는 헤더에 jQuery 선언문을 넣는다. -->
<script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<style>
header ul, header ul li {
margin: 0;
padding: 0;
display: inline;
}
header .category {
font-size: 18px;
}
header .category ul li:not(:first-child) { /* 첫번째 li만 빼고 지정 */
padding-left: 30px;
}
header .category ul li a:hover, header .category ul li a.active {
font-weight: bold;
color: #0000cd;
}
#userid, #userpw {
width: 100px;
height: 18px;
font-size: 14px;
}
header ul li input { display:block; }
</style>
<header style="border-bottom: 1px solid #ccc; padding: 15px 0; text-align: left">
<div class="category" style="margin-left: 100px;">
<ul>
<li><a href="<core:url value='/' />"><img src="img/logo.png" /></a></li>
<li><a href='list.cu' ${category eq 'cu' ? "class='active'" : '' } >고객 관리</a></li>
<li><a href='list.no'>공지사항</a></li>
<li><a href='list.bo'>방명록</a></li>
<li><a href='list.da'>공공 데이터</a></li>
</ul>
</div>
<div style="position: absolute; right: 0; top: 25px; margin-right: 100px;">
<!-- 로그인한 경우 -->
<core:if test="${!empty login_info }">
<ul>
<li>홍길동 [hong]</li>
<li><a class="btn-fill">로그아웃</a></li>
</ul>
</core:if>
<!-- 로그인하지 않은 경우 -->
<core:if test="${empty login_info }">
<ul>
<li>
<span style="position: absolute; top: -14px; left: -120px">
<input type="text" id="userid" placeholder="아이디" />
<input type="password" id="userpw" placeholder="비밀번호" />
</span>
</li>
<li><a class="btn-fill" onclick="go_login()">로그인</a></li>
<li><a class="btn-fill">회원가입</a></li>
</ul>
</core:if>
</div>
</header>
<script>
function go_login() {
if( $('#userid').val() == '' ) {
alert('아이디를 입력하세요!');
$('#userid').focus();
return;
} else if( $('#userpw').val() == '' ) {
alert('비밀번호를 입력하세요!');
$('#userpw').focus();
return;
}
$.ajax({
type: 'post',
url: 'login',
data: { id:$('#userid').val(), pw:$('#userpw').val() },
success: function() {},
error: function(req, text) { alert(text + ': ' + req.status} }
});
}
</script>
▲header.jsp
package com.hanul.iot;
import java.util.List;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import customer.CustomerServiceImpl;
import customer.CustomerVO;
@Controller
public class CustomerController {
@Autowired private CustomerServiceImpl service;
//컨트롤러 - 서비스 - DAO - 맵퍼 순으로 연결된다.
//고객 관리 목록 화면
@RequestMapping("/list.cu")
public String list(HttpSession session, Model model) {
//서블릿에서는 request에서 getsession으로 세션을 가져왔다면,
//스프링에서는 바로 세션에 접근할 수 있게 HttpSession을 지원한다.
//category 어트리뷰트의 값에 따라 active 속성을 결정한다.
session.setAttribute("category", "cu"); //카테고리 어트리뷰트에 cu를 설정
List<CustomerVO> list = service.customer_list();
model.addAttribute("list", list);
return "customer/list";
}
//고객 상세 화면 요청
@RequestMapping("/detail.cu")
public String detail(int id, Model model) {
//선택한 고객 정보를 DB에 조회해와서
CustomerVO vo = service.customer_detail(id);
//화면에 출력할 수 있도록 Model에 담는다.
//원래는 string타입으로 담겨야하지만 스프링에서는 자동으로 형변환이 되서 int타입으로 담긴다.
model.addAttribute("vo", vo);
return "customer/detail";
}
//신규 고객 등록 화면 요청
@RequestMapping("/new.cu")
public String customer() {
return "customer/new";
}
//20/07/02====================================================
//신규 고객 등록 처리 요청
@RequestMapping("/insert.cu")
public String insert(CustomerVO vo) {
//화면에서 입력한 정보를 DB에 저장한 후
service.customer_insert(vo);
//목록 화면으로 연결
return "redirect:list.cu";
}
//고객 정보 수정 화면 요청
@RequestMapping("/modify.cu")
public String modify(int id, Model model) {
//선택한 고객의 정보를 DB에서 조회해온 후
//수정 화면에 출력할 수 있도록 Model에 담는다
model.addAttribute("vo", service.customer_detail(id));
return "customer/modify";
}
//고객 정보 수정 저장 처리 요청
@RequestMapping("/update.cu")
public String update(CustomerVO vo) {
//화면에서 수정 입력한 정보를 DB에 저장한 후
service.customer_update(vo);
//화면으로 연결
return "redirect:detail.cu?id=" + vo.getId();
}
//고객 정보 삭제 처리 요청
@RequestMapping("/delete.cu")
public String delete(int id) {
//선택한 고객 정보를 DB에서 삭제한 후
service.customer_delete(id);
//목록 화면으로 연결
return "redirect:list.cu";
}
}
▲CustomerController.java
package customer;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service //서비스 역할을 하는 클래스를 객체로 만들어둘때 사용
public class CustomerServiceImpl implements CustomerService {
@Autowired private CustomDAO dao;
@Override
public void customer_insert(CustomerVO vo) {
dao.customer_insert(vo);
}
@Override
public List<CustomerVO> customer_list() {
return dao.customer_list();
}
@Override
public CustomerVO customer_detail(int id) {
return dao.customer_detail(id);
}
@Override
public void customer_update(CustomerVO vo) {
dao.customer_update(vo);
}
@Override
public void customer_delete(int id) {
dao.customer_delete(id);
}
}
▲CustomerServiceImpl.java
package customer;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
//어노테이션은 클래스를 객체로 생성하는 역할을 해줌
//@Component는 다용도, 특정역할이 있으면 역할군에 맞는 어노테이션을 사용한다.
@Repository //저장소 역할을 하는 클래스를 객체로 만들때 사용
public class CustomDAO implements CustomerService {
@Autowired private SqlSession sql;
//SqlSession : PreparedStatement와 표현 방법이 다를뿐 같은 기능을 한다.
//Autowired : 메모리에 올려둔 주소들이 자동으로 연결 됨
@Override
public void customer_insert(CustomerVO vo) {
sql.insert("customer.mapper.insert", vo);
}
@Override
public List<CustomerVO> customer_list() {
//customer.mapper라는 맵퍼에서 id가 list인 곳을 찾는다
return sql.selectList("customer.mapper.list");
}
@Override
public CustomerVO customer_detail(int id) {
return sql.selectOne("customer.mapper.detail", id);
}
@Override
public void customer_update(CustomerVO vo) {
sql.update("customer.mapper.update", vo);
}
@Override
public void customer_delete(int id) {
sql.delete("customer.mapper.delete", id);
}
}
▲CustomDAO.java
<?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="customer.mapper">
<!-- resultType : 반환될 데이터타입 -->
<select id="detail" resultType="customer.CustomerVO">
SELECT * FROM customer WHERE id=#{id }
</select>
<!-- 애스터리스크(*)를 쓰면 ROWNUM 등의 다른 필드를 쓸 수가 없다. -->
<select id="list" resultType="customer.CustomerVO">
SELECT ROWNUM no, c.* FROM (SELECT * FROM customer ORDER BY name) c
</select>
<insert id="insert">
INSERT INTO customer(name, gender, email, phone)
VALUES (#{name }, #{gender }, #{email }, #{phone })
</insert>
<update id="update">
UPDATE customer SET gender=#{gender }, email=#{email }, phone=#{phone }
WHERE id=#{id }
</update>
<delete id="delete">
DELETE FROM customer WHERE id=#{id }
</delete>
</mapper>
▲customer-mapper.xml
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>detail JSP</title>
</head>
<body>
<jsp:include page="/WEB-INF/views/include/header.jsp" />
<div id="content">
<h3>[ ${vo.name } ]고객 정보</h3>
<table class='w-pct60'>
<tr>
<th class='w-px160'>성별</th>
<td>${vo.gender }</td>
</tr>
<tr>
<th>이메일</th>
<td>${vo.email }</td>
</tr>
<tr>
<th>전화번호</th>
<td>${vo.phone }</td>
</tr>
</table>
<div class='btnSet'>
<a class='btn-fill' href="list.cu">고객 목록</a>
<a class='btn-fill' href="new.cu">신규 고객</a>
<a class='btn-fill' href="modify.cu?id=${vo.id }">수정</a>
<a class='btn-fill' onclick="if( confirm('정말 삭제하시겠습니까?') ){ href='delete.cu?id=${vo.id }' }" >삭제</a>
</div>
</div>
<jsp:include page="/WEB-INF/views/include/footer.jsp" />
</body>
</html>
▲detail.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>modify JSP</title>
</head>
<body>
<jsp:include page="/WEB-INF/views/include/header.jsp" />
<div id="content">
<h3>[ ${vo.name } ]고객 정보 수정</h3>
<form action="update.cu" method="post">
<input type="hidden" name="id" value="${vo.id }" />
<!-- 수정할 고객을 특정하기 위해 id가 필요한데 수정 내용에는 id가 없으므로 hidden 속성으로 추가 -->
<table class="w-pct60">
<tr>
<th class="w-px160">성별</th>
<td>
<label><input type="radio" name="gender" value="남" ${vo.gender eq '남' ? "checked" : '' }/>남</label>
<label><input type="radio" name="gender" value="여" ${vo.gender eq '여' ? "checked" : '' }/>여</label>
</td>
</tr>
<tr>
<th>이메일</th>
<td><input type="text" name="email" value="${vo.email }" /></td>
</tr>
<tr>
<th>전화번호</th>
<td><input type="text" name="phone" value="${vo.phone }"/></td>
</tr>
</table>
</form>
<div class='btnSet'>
<a class="btn-fill" onclick="$('form').submit()">저장</a>
<a class="btn-empty" href="detail.cu?id=${vo.id }">취소</a>
</div>
</div>
<jsp:include page="/WEB-INF/views/include/footer.jsp" />
</body>
</html>
▲modify.jsp
--테이블 생성
CREATE TABLE customer (
id NUMBER CONSTRAINT customer_id_pk PRIMARY KEY,
name VARCHAR2(50) NOT NULL,
gender VARCHAR2(3) NOT NULL,
email VARCHAR2(50),
phone VARCHAR2(13)
);
--시퀀스 생성
CREATE SEQUENCE seq_customer START WITH 1 INCREMENT BY 1;
--레코드 삽입
INSERT INTO customer(id, name, gender)
VALUES (seq_customer.NEXTVAL, '홍길동', '남');
INSERT INTO customer(name, gender)
VALUES ('심청', '여');
--트리거(trigger) 설정
CREATE OR REPLACE TRIGGER trg_customer
BEFORE INSERT ON customer --커스터머 테이블에 인서트가 되기전에
FOR EACH ROW --모든 행에 대하여
BEGIN --시작한다
SELECT seq_customer.NEXTVAL INTO :new.id FROM dual; --시퀀스의 데이터를 담고있는 테이블은 없으므로 더미 테이블(dual)에서 조회한다.
END;
/ --끝 슬래쉬까지 써줘야한다
drop trigger trg_customer;
CREATE OR REPLACE TRIGGER trg_customer
BEFORE INSERT ON customer
FOR EACH ROW
BEGIN
SELECT seq_customer.NEXTVAL INTO :new.id FROM dual;
END;
/
--조회
SELECT * FROM customer;
--커밋
COMMIT;
--20/07/02==================================================================
--회원 관리 테이블
CREATE TABLE member(
irum VARCHAR2(20) NOT NULL,
id VARCHAR2(20) CONSTRAINT member_id_pk PRIMARY KEY,
pw VARCHAR2(20) NOT NULL,
age NUMBER,
gender VARCHAR2(3) NOT NULL,
birth DATE,
post VARCHAR2(7),
addr VARCHAR2(50),
email VARCHAR2(50) NOT NULL, --유니크가 들어간다 생각하고 NOT NULL만 지정
tel VARCHAR2(20),
admin VARCHAR2(1) DEFAULT 'N'
);
--기존에 있던 member 테이블 수정
ALTER TABLE member
ADD(
gender VARCHAR2(3) DEFAULT '남' NOT NULL,
birth DATE,
post VARCHAR2(7),
email VARCHAR2(50),
admin VARCHAR2(1) default 'N'
);
UPDATE MEMBER SET email = id || '@naver.com';
ALTER TABLE member
MODIFY (irum NOT NULL, pw NOT NULL, email NOT NULL);
ALTER TABLE member RENAME COLUMN irum TO name;
ALTER TABLE member ADD CONSTRAINT member_id_pk PRIMARY KEY(id);
--관리자 회원 정보 저장
INSERT INTO member(name, id, pw, age, gender, email, admin)
VALUES ('관리자', 'admin', '1234', 25, '남', 'admin@admin.com', 'Y');
SELECT * FROM member;
▲table.sql
반응형