|
Back-End/Spring 2019. 6. 17. 14:01
-관리자 로그인/로그아웃 기능 구현-
-관리자 로그인 전체 구조-
( 뷰 => 컨트롤러 => 서비스 => 모델(DAO) => mapper => 컨트롤러 => 뷰) (admin) login 페이지에서 로그인 버튼을 클릭하면 id값인 "btnLogin"가
login 페이지 상부에 있는 자바스크립트 구문에 EL태그에 맵핑되서 click()메소드
안에 있는 함수가 실행되서 userid값과 passwd값을 가져와 내가 입력한 id값과 pass값과
맞는지 확인해서 일치하면 Admincontroller에 있는 login_check.do에 맵핑되어 있는 메소드와 연결한다.
맵핑된 메소드에서는 서비스를 호출하고 서비스에서는 dto를 매개값으로 받아서 DAO에 리턴한다.
DAO에서는 mybatis mapper을 호출해야하기 때문에 의존성을 주입한 sqlsession을 사용하고,
DAO 인터페이스에서 만든 메소드를 구현해서 namespace값과 id값, resultType을 확인해 일치하는
Mapper에 연결해서 sql쿼리를 (dto를 매개값으로 삼아서) sqlsession에 담는다.
다시 controller로 돌아와서 name(서비스에 담긴값을 저장한 변수)에 담긴 값이 null이 아니면 (로그인이 성공했다면..)
session에 setAttribute()메소드를 사용해서 관리자 id와 이름을 session에 저장하고,
ModelAndView 타입의 변수를 사용해서 보여줄 페이지와 보낼 값(로그인 성공 메시지)을 설정한다.
로그인이 성공하면 View (admin)페이지로 이동하고, 넘어갈때 success (메시지 값)이 같이 넘어갔기 때문에
ex) dlgkstjq12(이한섭)님 환영합니다. 와 같이 출력이 된다.
|
-관리자 로그아웃 전체 구조-
(뷰 => 컨트롤러 => 뷰)
View에 있는 logout.do와 controller에 있는 logout.do를 맵핑해서 session의 invalidate( ) 메소드를 실행한다.
invalidate( ) 메소드는 session 내부에있는 데이터를 초기화 시키는 메소드이다. 삭제 시킨후에는 redirect로 login페이지로 이동한다.
|
관리자 테이블 만들기
관리자가 로그인 한 후에 상품의 정보를 수정, 추가, 삭제 할 수 있도록 할 예정 권한에다가 1부터 9까지 주고, 예를 들면 숫자 9면 최고 관리자라는 식으로 할 수도 있다.
| create table admin ( userid varchar2(50) not null, //not null은 null값이 들어가지 못한다는 의미 passwd varchar2(50) not null, name varchar2(50) not null, email varchar2(100), join_date date default sysdate, primary key(userid) ); | cs |
| insert into admin (userid, passwd, name) values ('admin','1234','관리자'); | cs |
AdminDAO.java | package com.example.spring02.model.admin; import com.example.spring02.model.member.dto.MemberDTO; public interface AdminDAO { public String loginCheck(MemberDTO dto); //dto를 받아서 관리자 로그인을 체크하는 메소드 } | cs |
AdminDAOImpl.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | package com.example.spring02.model.admin; import javax.inject.Inject; import org.apache.ibatis.session.SqlSession; import org.springframework.stereotype.Repository; import com.example.spring02.model.member.dto.MemberDTO; @Repository //DAO를 구현한 클래스이므로 Repository 어노테이션을 사용 public class AdminDAOImpl implements AdminDAO { @Inject //mybatis mapper을 호출해야 하므로 sqlsession에 inject로 의존성을 주입하고 사용한다. SqlSession sqlSession; @Override //DAO 인터페이스에서 만든 메소드를 구현 public String loginCheck(MemberDTO dto) { return sqlSession.selectOne("admin.login_check", dto); //sqlsession에 mapper에 맵핑된 namespace와 id로 sql문을 저장한다. } } | cs |
adminMapper.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와 중복되지 않도록 네임스페이스 기재 --> <mapper namespace="admin"> <select id="login_check" resultType="String"> select name from admin where userid=#{userid} and passwd=#{passwd} </select> </mapper> | cs |
AdminService.java | package com.example.spring02.service.admin; import com.example.spring02.model.member.dto.MemberDTO; public interface AdminService { public String loginCheck(MemberDTO dto); //dto에 저장되어있는 정보를 받아 로그인을 체크하는 메소드 } | cs |
AdminServiceImpl.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | package com.example.spring02.service.admin; import javax.inject.Inject; import org.springframework.stereotype.Service; import com.example.spring02.model.admin.AdminDAO; import com.example.spring02.model.member.dto.MemberDTO; @Service //service이므로 service어노테이션을 사용함 public class AdminServiceImpl implements AdminService { @Inject AdminDAO adminDao; //dao를 호출해야하므로 inject로 의존성을 주입하고 사용 @Override public String loginCheck(MemberDTO dto) { return adminDao.loginCheck(dto); //dto에서 정보를 받고 dao에 리턴한다. } } | cs |
AdminController.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | package com.example.spring02.controller.admin; import javax.inject.Inject; import javax.servlet.http.HttpSession; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.example.spring02.model.member.dto.MemberDTO; import com.example.spring02.service.admin.AdminService; @Controller //컨트롤러로 사용하기위한 어노테이션 사용 @RequestMapping("/admin/*") //RequestMapping를 사용해서 공통된 부분을 맵핑 public class AdminController { @Inject AdminService adminService; //service객체를 사용해야 하므로 inject로 의존성을 주입받아서 스프링에서 관리하게 한다. @RequestMapping("login.do") // view (menu.jsp)에서 RequestMapping된 메소드 public String login() { return "admin/login"; //admin디렉터리 하위에 있는 login.jsp 파일을 보여준다는 뜻 } //view에서 login_check.do를 맵핑하면 이 메소드가 호출된다. @RequestMapping("login_check.do") public ModelAndView login_check( //이 메소드는 dto, session, mav를 매개값으로 받고, session안에 setAttribute 메소드를 사용해서 값들을 저장한다. MemberDTO dto, HttpSession session, ModelAndView mav) { //ModelAndView는 데이터를 출력할 페이지와 전송을 동시에 함 String name=adminService.loginCheck(dto); if(name != null) { //로그인 성공 (그러니까 loginCheck()메소드 안에 이름이 저장되어있다는 뜻) //dto에서 Userid()를 받아와 admin_userid라는 이름으로 session에 setAttribute()메소드를 사용해서 저장하고 //name도 마찬가지로 session에 저장한다. session.setAttribute("admin_userid", dto.getUserid()); session.setAttribute("admin_name", name); //dto에서 Userid()를 받아와 userid라는 이름으로 session에 setAttribute() 메소드를 사용해서 저장하고 //name도 마찬가지로 session에 저장한다. session.setAttribute("userid", dto.getUserid()); session.setAttribute("name", name); mav.setViewName("admin/admin"); //admin페이지를 보여준다는 뜻 mav.addObject("message", "success"); //mav안에 있는 addObject()메소드를 사용해 message라는 키에 sucess라는 value를 담아 보낸다 }else { mav.setViewName("admin/login"); //관리자 로그인이 실패했을때 보여주는 페이지 mav.addObject("message", "error"); //error메시지를 출력한다. } return mav; } //관리자 로그아웃 처리 //View에 있는 logout.do를 맵핑 @RequestMapping("logout.do") public String logout(HttpSession session) { session.invalidate(); //로그아웃을 시키려면 session에 있는 데이터를 삭제시켜야 하기 때문에 invalidate()메소드를 사용해서 //안에 있는 데이터를 초기화 시킨다. return "redirect:/admin/login.do"; //데이터를 삭제시킨후에는 login페이지로 돌아가도록 한다. } } | cs |
login.jsp (관리자용) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <!-- 관리자 로그인 페이지 --> <%@ include file="../include/header.jsp"%> <script> //button을 클릭하면 아이디와 비밀번호를 처리해서 Controller에 있는 login_check로 맵핑시킨다. //아이디와 비밀번호를 받아 처리하는 자바스크립트 구문 $(function(){ $("#btnLogin").click(function(){ //밑에 있는 button태그로 쓴 id값이 이쪽으로 맵핑되서 넘어오고, click()메소드 안에 함수가 실행 var userid=$("#userid").val(); //밑에있는 input문으로 가져온 userid의 값을 val()메소드를 사용해 가져오고, 그 값을 userid 변수에 넣는다. var passwd=$("#passwd").val(); //밑에 있는 input문으로 가져온 passwd의 값을 val()메소드를 사용해 가져오고, 그 값을 passwd 변수에 넣는다. if(userid == ""){ //userid에 아무것도 입력이 되지 않으면 alert("아이디를 입력하세요."); //경고창 출력 $("#userid").focus(); //focus()메소드는 커서를 옮겨놓는 효과, 그러니까 아이디 입력창에 자동으로 커서가 옮겨져 있는다. 깜빡이게끔 return; } if(passwd==""){ //마찬가지로 passwd가 아무것도 입력이 되지 않으면 alert("비밀번호를 입력하세요."); //경고창 출력 $("#passwd").focus(); //focus()메소드는 커서를 옮겨놓는 효과, 그러니까 아이디 입력창에 자동으로 커서가 옮겨져 있는다. 깜빡이게끔 return; } document.form1.action = "${path}/admin/login_check.do"; //밑에 form1 폼을 Controller의 login_check에 맵핑하도록 한다. document.form1.submit(); //자료를 선송 }); }); </script> </head> <body> <%@ include file="../include/menu.jsp"%> <h2>관리자 로그인</h2> <form name="form1" method="post"> <table border="1" method="post"> <tr> <td>아이디</td> <td><input id="userid" name="userid"></td> </tr> <tr> <td>비밀번호</td> <td><input type="password" id="passwd" name="passwd"></td> </tr> <tr> <td colspan="2" align="center"> <button type="button" id="btnLogin">로그인</button> <c:if test="${param.message == 'nologin' }"> <div style="color: red;">먼저 로그인하세요.</div> </c:if> <!-- c:if문 test의 값이 참이면 실행. (로그인이 아예안되어 있으면 실행)--> <!-- 로그인이 안되었다는 값이 넘어오면 빨간색으로 경고창 출력--> <c:if test="${message == 'error' }"> <div style="color: red;">아이디 또는 비밀번호가 일치하지 않습니다.</div> </c:if> <!-- c:if문 test의 값이 참이면 실행. (아이디나 비밀번호중 하나가 일치하지 않으면)--> <!-- 아이디나 비밀번호가 일치하지 않으면 빨간색으로 경고 메시지 출력--> <c:if test="${message == 'logout' }"> <div style="color: red;">로그아웃되었습니다.</div> </c:if> <!-- c:if문 test의 값이 참이면 실행. 로그아웃 메시지가 출력되면....--> <!-- 로그아웃이 되면 로그아웃되었습니다. 메시지를 출력함--> </td> </tr> </table> </form> </body> </html> | cs |
admin.jsp (관리자 로그인시 출력되는 페이지) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <%@ include file="../include/header.jsp" %> </head> <body> <%@ include file="../include/admin_menu.jsp" %> <c:if test="${message == 'success' }"> <!-- controller에서 보낸 메시지의 값이 success면 c:if문이 실행이 된다.--> <h2> ${sessionScope.admin_name} (${sessionScope.admin_userid})님 환영합니다. <!--sessionScope는 세션에 담은 setAttribute()메소드 안에 있는 값을 jsp에서 JSTL로 간단히 사용하고 싶을때 사용하면 된다. --> <!--ex) dlgkstjq12(이한섭)님 환영합니다. 와 같이 출력됨. --> </h2> </c:if> </body> </html> | cs |
Back-End/Spring 2019. 6. 14. 23:11
-장바구니 기능 구현-
데이터베이스에서 cart 테이블을 생성
|
create table cart(
cart_id number not null primary key, //cart_id를 null값이 오지못하게 하고 기본키로 설정함
userid varchar2(50) not null, //userid를 null값이 오지못하게 설정
product_id number not null, //product_id를 null값이 오지못하게 설정
amount number default 0 //amount속성을 기본값을 0으로 설정
);
|
cs |
cart테이블에 제약조건을 추가한다.
(cart테이블에 cart_userid_fk라는 이름의 제약조건을 cart테이블에 있는 userid에 추가하고,
userid를 다른 테이블의 기본키를 참조하는 외래키로 설정하고, member테이블의 userid를 참조하도록 설정한다.)
(즉, member테이블의 userid가 변경되면 cart테이블에 있는 userid도 같이 변경된다는 뜻이다.)
만약에 cart테이블에 "insert into cart values (2,'kim',2,10)" 쿼리를 실행시켰을 때,
member테이블에 id (kim)이라는 id값이 없기 때문에 자료를 넣을 수 없어 오류가 발생한다.
즉, member 테이블에 존재하는 id값만 cart 테이블에 넣을 수 있다는 뜻이다.
(이렇게 하는 이유는 id값이 서로 일치하지 않아서 오류가 발생할 수 있기 때문에 제약조건을 설정하는 것이다.)
|
alter table cart add constraint cart_userid_fk
foreign key(userid) references member(userid);
|
cs |
아래 3개의 테이블을 참조해서 서로 join한다.
select name, product_name,price,amount,price*amount money
//회원의 이름과, 상품의 이름,물건 한개의 가격, 장바구니에 담은 개수, 총 물건의 가격을 검색한다.
from member m, product p, cart c
//member테이블과, product테이블과, cart테이블로부터 검색
where m.userid=c.userid and p.product_id=c.product_id;
//member의 userid와 cart의 userid가 같고, product의 product_id와 cart의 product_id가 같을때
//즉, 회원의 아이디와 상품을 사려는 회원이 같고, 상품의 번호와 카트의 번호가 같을때
|
장바구니 테이블을 만들었으므로 테이블에 있는 데이터를 저장할 클래스가 필요하다.
DTO 클래스를 생성
CartDTO.java (테이블 3개를 join할 것을 대비해서 필드와 getter, setter을 생성한다)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
package com.example.spring02.model.shop.dto;
public class CartDTO {
private int cart_id;
private String userid;
private String name;
private int product_id;
private String product_name;
private int price;
private int money;
private int amount;
public int getCart_id() {
return cart_id;
}
public void setCart_id(int cart_id) {
this.cart_id = cart_id;
}
public String getUserid() {
return userid;
}
public void setUserid(String userid) {
this.userid = userid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getProduct_id() {
return product_id;
}
public void setProduct_id(int product_id) {
this.product_id = product_id;
}
public String getProduct_name() {
return product_name;
}
public void setProduct_name(String product_name) {
this.product_name = product_name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
@Override
public String toString() {
return "CartDTO [cart_id=" + cart_id + ", userid=" + userid + ", name=" + name + ", product_id=" + product_id
+ ", product_name=" + product_name + ", price=" + price + ", money=" + money + ", amount=" + amount + "]";
}
}
|
cs |
CartDAO 인터페이스를 생성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package com.example.spring02.model.shop.dao;
import java.util.List;
import com.example.spring02.model.shop.dto.CartDTO;
public interface CartDAO {
List<CartDTO> cartMoney();
void insert(CartDTO dto); //장바구니 추가
List<CartDTO> listCart(String userid); //장바구니 목록
void delete(int cart_id); //장바구니 개별 삭제
void deleteAll(String userid); //장바구니 비우기
void update(int cart_id);
int sumMoney(String userid); //장바구니 금액 합계
int countCart(String userid, int product_id); //장바구니 상품 갯수
void updateCart(CartDTO dto); //장바구니 수정
void modifyCart(CartDTO dto);
}
|
cs |
CartDAOImpl.java (DAO 인터페이스 구현 클래스)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
package com.example.spring02.model.shop.dao;
import java.util.List;
import javax.inject.Inject;
import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;
import com.example.spring02.model.shop.dto.CartDTO;
@Repository
public class CartDAOImpl implements CartDAO {
//MyBatis를 호출하므로 sqlsession에 의존성을 주입해야한다.
@Inject
SqlSession sqlSession;
@Override
public List<CartDTO> cartMoney() {
// TODO Auto-generated method stub
return null;
}
//장바구니에 담기
@Override
public void insert(CartDTO dto) {
//dto에 저장된 값을 받아서 sql세션에 저장하고 cart.insert로 넘어감 mapper로.
sqlSession.insert("cart.insert", dto);
}
@Override
public List<CartDTO> listCart(String userid) {
return sqlSession.selectList("cart.listCart", userid);
}
@Override
public void delete(int cart_id) {
sqlSession.delete("cart.delete", cart_id);
}
@Override
public void deleteAll(String userid) {
sqlSession.delete("cart.deleteAll", userid);
}
@Override
public void update(int cart_id) {
// TODO Auto-generated method stub
}
@Override
public int sumMoney(String userid) {
return sqlSession.selectOne("cart.sumMoney", userid);
}
@Override
public int countCart(String userid, int product_id) {
// TODO Auto-generated method stub
return 0;
}
@Override
public void updateCart(CartDTO dto) {
// TODO Auto-generated method stub
}
@Override
public void modifyCart(CartDTO dto) {
sqlSession.update("cart.modify", dto);
}
}
|
cs |
sql세션에 dto에서 받은 값을 저장한 다음 mapper로 넘어간다.
cartMapper.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<?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와 중복되지 않도록 네임스페이스 기재 -->
<mapper namespace="cart">
<!-- 장바구니에 담기 -->
<insert id="insert">
insert into cart (cart_id, userid, product_id, amount)
values
(seq_cart.nextval, #{userid}, #{product_id}, #{amount} )
//장바구니 담기 버튼을 누를때 실행되는 쿼리문
//cart_id와 userid, product_id, amount 값을 저장한다.
//cart_id는 하나씩 증가되어야하기때문에 시퀀스값으로 지정한다.
</insert>
|
cs |
CART 테이블에 시퀀스를 생성
(시퀀스를 생성하고 그 시퀀스의 시작값은 1로 하고 1씩 증가한다.)
|
create sequence seq_cart
start with 1
increment by 1;
|
cs |
Service 생성
CartService.java (서비스 인터페이스 생성)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package com.example.spring02.service.shop;
import java.util.List;
import com.example.spring02.model.shop.dto.CartDTO;
public interface CartService {
List<CartDTO> cartMoney();
void insert(CartDTO dto);
List<CartDTO> listCart(String userid);
void delete(int cart_id);
void deleteAll(String userid);
void update(int cart_id);
int sumMoney(String userid);
int countCart(String userid, int product_id);
void updateCart(CartDTO dto);
void modifyCart(CartDTO dto);
}
|
cs |
CartServiceImpl.java (서비스 인터페이스 구현 클래스 생성)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
package com.example.spring02.service.shop;
import java.util.List;
import javax.inject.Inject;
import org.springframework.stereotype.Service;
import com.example.spring02.model.shop.dao.CartDAO;
import com.example.spring02.model.shop.dto.CartDTO;
@Service //Service 단이라는 것을 표시
public class CartServiceImpl implements CartService {
@Inject //dao를 사용해야하기 때문에 @Inject로 의존성 부여
CartDAO cartDao;
@Override
public List<CartDTO> cartMoney() {
return null;
}
@Override
public void insert(CartDTO dto) {
cartDao.insert(dto);
}
@Override
public List<CartDTO> listCart(String userid) {
return cartDao.listCart(userid);
}
@Override
public void delete(int cart_id) {
cartDao.delete(cart_id);
}
@Override
public void deleteAll(String userid) {
cartDao.deleteAll(userid);
}
@Override
public void update(int cart_id) {
// TODO Auto-generated method stub
}
@Override
public int sumMoney(String userid) {
return cartDao.sumMoney(userid);
}
@Override
public int countCart(String userid, int product_id) {
// TODO Auto-generated method stub
return 0;
}
@Override
public void updateCart(CartDTO dto) {
// TODO Auto-generated method stub
}
@Override
public void modifyCart(CartDTO dto) {
cartDao.modifyCart(dto);
}
}
|
cs |
CartController.java (장바구니 컨트롤러)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
//컨트롤러에서 메소드의 파라미터들은 갯수제한이 없고, 순서가 상관이 없다.
@RequestMapping("insert.do") //세부적인 url mapping
public String insert(@ModelAttribute CartDTO dto,
HttpSession session) {
//@ModelAttribute는 sumit된 form의 내용을 저장해서 전달받거나, 다시 뷰로 넘겨서 출력하기 위해 사용되는 오브젝트 이다.
//도메인 오브젝트나 DTO의 프로퍼티에 요청 파라미터를 바인딩해서 한번에 받으면 @ModelAttribute 라고 볼 수 있다.
//@ModelAttribute는 컨트롤러가 리턴하는 모델에 파라미터로 전달한 오브젝트를 자동으로 추가해준다.
//로그인 여부를 체크하기 위해 세션에 저장된 아이디 확인
String userid=(String)session.getAttribute("userid");
if(userid==null) {
//로그인하지 않은 상태이면 로그인 화면으로 이동
return "redirect:/member/login.do";
}
dto.setUserid(userid);
cartService.insert(dto); //장바구니 테이블에 저장됨
return "redirect:/shop/cart/list.do"; //장바구니 목록으로 이동
}
|
cs |
CartController.java 중 일부 (장바구니 리스트 관련 메소드)
cartlist.jsp 페이지와 맵핑됨
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
//cart_list페이지와 맵핑되는 메소드
@RequestMapping("list.do")
public ModelAndView list(HttpSession session, ModelAndView mav) {
Map<String, Object> map=new HashMap<>();
//hashmap은 map(key,value)로 이뤄져 있고,
//key값은 중복이 불가능 하고 value는 중복이 가능하다.
//value에 null값도 사용이 가능하다.
//전달할 정보가 많을 경우에는 HashMap<>을 사용하는 것이 좋다.
//장바구니에 담을 값들이 많기 때문에 여기선 HashMap<>를 사용한다.
String userid=(String)session.getAttribute("userid");
//session에 저장된 userid를 getAttribute()메소드를 사용해서 얻어오고 오브젝트 타입이기 때문에
//String 타입으로 타입변환한다.
if(userid!=null) {
//로그인한 상태이면 실행
List<CartDTO> list=cartService.listCart(userid);//장바구니 목록
int sumMoney=cartService.sumMoney(userid);//금액 합계
int fee=sumMoney >= 30000 ? 0 : 2500;
//배송료 계산
//30000원이 넘으면 배송료가 0원, 안넘으면 2500원
//hasp map에 장바구니에 넣을 각종 값들을 저장함
map.put("sumMoney", sumMoney);
map.put("fee", fee); //배송료
map.put("sum", sumMoney+fee); //전체 금액
map.put("list", list); //장바구니 목록
map.put("count", list.size()); //레코드 갯수
//ModelAndView mav에 이동할 페이지의 이름과 데이터를 저장한다.
mav.setViewName("shop/cart_list"); //이동할 페이지의 이름
mav.addObject("map", map); //데이터 저장
return mav; //화면 이동
}else { //로그인하지 않은 상태
return new ModelAndView("member/login", "", null);
//로그인을 하지 않았으면 로그인 페이지로 이동시킨다.
}
}
|
cs |
컨트롤러에서 로그인 여부를 알아야하고, 로그인한 상태이면 서비스와 DAO를 경유해서 mapper에서 "ListCart" id에 대한 쿼리를 실행시킨다.
CartServiceImpl.java (장바구니 서비스 구현 클래스) 중 일부
|
@Override
public List<CartDTO> listCart(String userid) {
return cartDao.listCart(userid);
}
|
cs |
CartDAOImpl.java (장바구니 DAO 구현 클래스) 중 일부
(ListCart태그가 호출된다)
|
@Override
public List<CartDTO> listCart(String userid) {
return sqlSession.selectList("cart.listCart", userid);
}
|
cs |
cartMapper.xml 중 일부
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<select id="listCart" resultType="com.example.spring02.model.shop.dto.CartDTO">
<!-- DAO에서 listCart라는 태그로 인해 실행되고 결과타입은 DTO타입으로 한다. (다른계층으로 보내기 위해서) -->
select cart_id, p.product_id, c.userid, name, product_name, amount, price, (price*amount) money
<!-- 장바구니의 번호, 상품 번호, 회원번호, 회원이름, 상품이름, 상품의양, 상품1개의 가격, 상품의 전체가격을 검색한다.-->
<!--양쪽 테이블에 다 있는 속성이면 어떤 테이블의 속성인지 정확히 표기해주어야 한다.--!>
from member m, cart c, product p
<!-- 회원테이블과, 장바구니 테이블과, 상품테이블로 부터 -->
where m.userid=c.userid and c.product_id=p.product_id and c.userid=#{userid} order by cart_id
<!--회원테이블의 회원id와 장바구니테이블의 회원id가 같고, 장바구니의 상품id와 상품테이블의 상품id가 같고, 장바구니테이블의 회원id가 장바구니에 저장되있는 회원id와 같을때-->
<!-- 장바구니에 관한 정보를 담은 sql문이다. -->
</select>
|
cs |
Mapper에서 SQL을 사용해서 검색한 목록을 list로 받아서 컨트롤러로 전달을 하고, 그 데이터를 바탕으로
sumMoney(총금액, 서비스와 DAO를 거쳐서 받고, 다시 Mapper을 거쳐서 컨트롤러로 받게됨)
CartServiceImpl.java (서비스 인터페이스 구현 클래스) 중 일부
|
@Override
public int sumMoney(String userid) {
return cartDao.sumMoney(userid);
}
|
cs |
CartDAOImpl.java (DAO 인터페이스 구현 클래스) 중 일부
|
@Override
public int sumMoney(String userid) {
return sqlSession.selectOne("cart.sumMoney", userid);
}
|
cs
|
cartMapper.xml 중 일부
(조인을 하는 이유는 장바구니 테이블에는 가격이 없기때문에 가격이 있는 다른 테이블과 join을 해야한다.)
|
<select id="sumMoney" resultType="int">
select nvl(sum(price*amount),0)
<!--금액과 상품갯수를 곱한값과 0을더해서 0이 나오는 것을 검색한다. -->
<!--그러니까 아무것도 담지 않았을때를 확인하는 것이다. -->
<!--빈값이 null이면 안되기 때문에 대체값으로 0이 출력되게끔 만들었다--!>
from cart c,product p
<!-- 장바구니 테이블과 상품 테이블로 부터 -->
where c.product_id=p.product_id and userid=#{userid}
<!--조건 : 장바구니테이블의 상품 id가 상품테이블의 상품 id와 같고, 요청하는 회원의 id와 같은 경우 -->
</select>
|
cs |
cart_list.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<%@ include file="../include/header.jsp" %>
<script>
$(function(){
$("#btnList").click(function(){
location.href="${path}/shop/product/list.do";
});
// 아래쪽에서 btnlist를 호출해서 실행되는 function() 함수 구문.
// list로 가는 링크를 만든다.
$("#btnDelete").click(function(){
if(confirm("장바구니를 비우시겠습니까?")){
location.href="${path}/shop/cart/deleteAll.do";
}
});
});
</script>
</head>
<body>
<%@ include file="../include/menu.jsp" %>
<h2>장바구니</h2>
<c:choose>
<c:when test="${map.count == 0 }">
<!-- when은 ~~일때 라는 뜻 그러니까 map의 count가 0일때... -->
<!-- xml파일에서 hashmap에 list를 넣어놓았기 때문에 현재 map에 자료가 들어있다. -->
<!-- map에 자료가 아무것도 없다면 -->
장바구니가 비었습니다.
</c:when>
<c:otherwise>
<!-- map.count가 0이 아닐때, 즉 자료가 있을때 -->
<!-- form을 실행한다. -->
<!-- form의 id를 form1로 하고, method 방식을 post로 한다. 그리고 update.do페이지로 이동시킨다. -->
<form id="form1" name="form1" method="post"
action="${path}/shop/cart/update.do">
<table border="1" width="400px">
<tr>
<th>상품명</th>
<th>단가</th>
<th>수량</th>
<th>금액</th>
<th> </th>
</tr>
<!-- map에 있는 list출력하기 위해 forEach문을 사용해 row라는 변수에 넣는다. -->
<c:forEach var="row" items="${map.list}">
<tr align="center">
<td>${row.product_name}</td>
<td><fmt:formatNumber value="${row.price}"
pattern="#,###,###" /></td>
<!-- fmt:formatNumber 태그는 숫자를 양식에 맞춰서 문자열로 변환해주는 태그이다 -->
<!-- 여기서는 금액을 표현할 때 사용 -->
<!-- ex) 5,000 / 10,000 등등등-->
<td><input type="number" name="amount"
style="width:30px;"
value="<fmt:formatNumber value="${row.amount}"
pattern="#,###,###" />">
<!-- 물건의 개수 (amount)를 fmt태그를 사용해서 패턴의 형식에 맞춰서 문자열로 변환함 -->
<!--1,000 / 5,000 등등~ -->
<input type="hidden" name="cart_id"
value="${row.cart_id}">
</td>
<td><fmt:formatNumber value="${row.money}"
pattern="#,###,###" /></td>
<td><a href=
"${path}/shop/cart/delete.do?cart_id=${row.cart_id}">[삭제]</a>
<!-- 삭제 버튼을 누르면 delete.do로 장바구니 개별 id (삭제하길원하는 장바구니 id)를 보내서 삭제한다. -->
</td>
</tr>
</c:forEach>
<tr>
<td colspan="5" align="right">
장바구니 금액 합계 :
<fmt:formatNumber value="${map.sumMoney}"
pattern="#,###,###" /><br>
배송료 : ${map.fee}<br>
총합계 : <fmt:formatNumber value="${map.sum}"
pattern="#,###,###" />
</td>
</tr>
</table>
<button id="btnUpdate">수정</button>
<button type="button" id="btnDelete">장바구니 비우기</button>
//btnUpdate와 btnDelete id는 위쪽에 있는 자바스크립트가 처리한다.
</form>
</c:otherwise>
</c:choose>
<button type="button" id="btnList">상품목록</button>
</body>
</html>
|
cs |
-장바구니 삭제-
( 뷰 => 컨트롤러 => 서비스 => 모델(DAO) => mapper => 컨트롤러 => 뷰) cart_list.jsp에 있는 delete을 호출하면
컨트롤러로 이동해 delete.do와 맵핑하고 서비스에 장바구니 id를 넘겨준다.
서비스에서는 넘겨받은 id를 DAO에 저장하고, DAO에서는 태그 아이디가 delete인 태그를 mapper에 전달하고, id도 전달한다.
mapper에서는 userid가 특정 id (사용자가 선택한 id)를 다 지우게끔 한다.
그리고 장바구니를 삭제한 후에 다시 컨트롤러로 돌아와 list.jsp 파일로 이동한다.
|
cart_list.jsp (View) 중 일부
|
<td>
<a href= "${path}/shop/cart/delete.do?cart_id=${row.cart_id}">[삭제]</a>
</td>
|
cs |
cartController.java 중 일부
|
@RequestMapping("delete.do")
public String delete(@RequestParam int cart_id) {
cartService.delete(cart_id);
return "redirect:/shop/cart/list.do";
}
|
cs |
cartServiceImpl.java 중 일부
|
@Override
public void delete(int cart_id) {
cartDao.delete(cart_id);
}
|
cs |
cartDAOImpl.java 중 일부
|
@Override
public void delete(int cart_id) {
sqlSession.delete("cart.delete", cart_id);
}
|
cs |
cartMapper.xml 중 일부
|
<!-- 장바구니 개별 상품 삭제 -->
<delete id="delete">
delete from cart where cart_id=#{cart_id}
</delete>
|
cs |
-장바구니 비우기-
( 뷰 => 컨트롤러 => 서비스 => 모델(DAO) => mapper => 컨트롤러 => 뷰 )
cart_list.jsp에 있는 javascript구문에서 deleteAll을 호출하면
컨트롤러로 이동해 deleteAll.do와 맵핑하고 세션에서 유저의아이디를 가져와서 null이 아닐경우에 서비스로 아이디를 넘긴다.
서비스에서는 넘겨받은 id로 DAO를 호출하고, DAO에서는 태그 아이디가 deleteAll인 태그를 mapper에 전달하고, id도 전달한다.
mapper에서는 userid가 특정 id (사용자가 선택한 id)를 다 지우게끔 한다.
그리고 장바구니를 전부다 비운 후에 다시 컨트롤러로 돌아와 list.jsp 파일로 이동한다.
|
cart_list.jsp (view)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<script>
$(function(){
$("#btnList").click(function(){
location.href="${path}/shop/product/list.do";
});
$("#btnDelete").click(function(){
if(confirm("장바구니를 비우시겠습니까?")){
location.href="${path}/shop/cart/deleteAll.do";
}
});
});
</script>
======================================================================
<button type="button" id="btnDelete">장바구니 비우기</button>
|
cs |
CartController.java (controller)
|
@RequestMapping("deleteAll.do")
public String deleteAll(HttpSession session) {
String userid=(String)session.getAttribute("userid");
if(userid!=null) {
cartService.deleteAll(userid);
}
return "redirect:/shop/cart/list.do";
}
|
cs |
CartServiceImpl.java (Service)
|
@Override
public void deleteAll(String userid) {
cartDao.deleteAll(userid);
}
|
cs |
CartDAOImpl.java (model-DAO)
|
@Override
public void deleteAll(String userid) {
cartDao.deleteAll(userid);
}
|
cs |
cartMapper.xml
|
<!-- 장바구니 비우기 -->
<delete id="deleteAll">
delete from cart where userid=#{userid}
<!-- 장바구니테이블로부터 회원의 아이디와 삭제하고자하는 회원의 아이디가 같으면 장바구니에 있는 자료를 전부다 삭제 -->
</delete>
|
cs |
아래 책은 제가 공부할때 활용했던 책으로 추천드리는 책이니 한번씩 읽어보시는것을 추천드립니다!! ㅎㅎ
![토비의 스프링 3.1 세트:스프링의 이해와 원리 + 스프링의 기술과, 에이콘출판](https://img3a.coupangcdn.com/image/affiliate/banner/90e4aecc4c937a47d53d6cd7f677bb0f@2x.jpg)
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
-장바구니 수정-
위의 삭제나 비우기와 구조가 거의 동일
Back-End/Problems 2019. 6. 13. 13:42
HTTP Status 500 – Internal Server Error
Type Exception Report Message Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: Description The server encountered an unexpected condition that prevented it from fulfilling the request. Exception org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for member.login_check
### Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for member.login_check
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1013)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908)
javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
Root Cause org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for member.login_check
### Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for member.login_check
org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:77)
org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446)
com.sun.proxy.$Proxy10.selectOne(Unknown Source)
org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:166)
com.example.spring02.model.member.dao.MemberDAOImpl.loginCheck(MemberDAOImpl.java:20)
com.example.spring02.service.member.MemberServiceImpl.loginCheck(MemberServiceImpl.java:26)
com.example.spring02.controller.member.MemberController.login_check(MemberController.java:41)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908)
javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
Root Cause org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for member.login_check
### Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for member.login_check
org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:150)
org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)
org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:77)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:433)
com.sun.proxy.$Proxy10.selectOne(Unknown Source)
org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:166)
com.example.spring02.model.member.dao.MemberDAOImpl.loginCheck(MemberDAOImpl.java:20)
com.example.spring02.service.member.MemberServiceImpl.loginCheck(MemberServiceImpl.java:26)
com.example.spring02.controller.member.MemberController.login_check(MemberController.java:41)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908)
javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
Root Cause java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for member.login_check
org.apache.ibatis.session.Configuration$StrictMap.get(Configuration.java:888)
org.apache.ibatis.session.Configuration.getMappedStatement(Configuration.java:721)
org.apache.ibatis.session.Configuration.getMappedStatement(Configuration.java:714)
org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:147)
org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)
org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:77)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:433)
com.sun.proxy.$Proxy10.selectOne(Unknown Source)
org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:166)
com.example.spring02.model.member.dao.MemberDAOImpl.loginCheck(MemberDAOImpl.java:20)
com.example.spring02.service.member.MemberServiceImpl.loginCheck(MemberServiceImpl.java:26)
com.example.spring02.controller.member.MemberController.login_check(MemberController.java:41)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908)
javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
Note The full stack trace of the root cause is available in the server logs.
Apache Tomcat/8.5.41
6월 13, 2019 11:57:14 오전 org.apache.catalina.core.StandardWrapperValve invoke 심각: Servlet.service() for servlet [appServlet] in context with path [/spring02] threw exception [Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: ### Error querying database. Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for member.login_check ### Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for member.login_check] with root cause java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for member.login_check
Back-End/Spring 2019. 6. 12. 18:23
- 상품관리 (로그인 / 로그아웃 기능 구현) -
세션을 사용해서 세션이 아이디와 비밀번호를 저장한 후 페이지를 이동해도 로그인 정보가 그대로 넘어가게 할 예정
뷰 => 컨트롤러 => 서비스 => 모델 => 뷰
-로그인-
menu.jsp 페이지에서 로그인 링크를 누르면 login.do( login.jsp 페이지 ) 로 이동.
login.jsp 페이지에서 아이디와 비밀번호를 입력하고 로그인 버튼을 누르면 id 값 (btnLogin) 이 위쪽에 있는 javaScript 구문으로 넘겨받아서
아이디와 비밀번호가 DTO와 DAO를 거쳐서 컨트롤러에 맵핑된 login_check로 넘어간다.
name값이 null값이 아니면 (로그인이 성공하면) home페이지로 이동하고, 로그인이 실패하면 login 페이지로 되돌아간다.
|
menu.jsp (로그인과 로그아웃 페이지로 이동하는 태그를 추가) | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %> <!-- 다른페이지에 include되는 페이지 --> <a href = "${path }/memo/list.do">한줄메모장</a> ㅣ <a href = "${path }/upload/uploadForm">업로드 테스트</a> ㅣ <a href = "${path }/shop/product/list.do">상품목록</a> ㅣ <div style = "text-align: right;"> <a href = "${path }/member/login.do">로그인</a> //login.do로 이동하는 링크를 만듬
<a href = "${path }/member/logout.do">로그아웃</a> //logout.do로 이동하는 링크를 만듬 </div> | cs |
회원테이블은 기존에 만들어놓은 테이블을 사용한다. (member 테이블)
MemberDTO.java (계층별 데이터 교환 클래스) member테이블에 있는 속성명과 맞춰서 만든다. (데이터를 넣고 빼고가 자유롭게...) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | package com.example.spring02.model.member.dto; import java.util.Date; public class MemberDTO { private String userid; private String passwd; private String name; private String email; private Date join_date; public String getUserid() { return userid; } public void setUserid(String userid) { this.userid = userid; } public String getPasswd() { return passwd; } public void setPasswd(String passwd) { this.passwd = passwd; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Date getJoin_date() { return join_date; } public void setJoin_date(Date join_date) { this.join_date = join_date; } @Override public String toString() { return "MemberDTO [userid=" + userid + ", passwd=" + passwd + ", name=" + name + ", email=" + email + ", join_date=" + join_date + "]"; } } | cs |
MemberDAO.java (DB연결 클래스) | package com.example.spring02.model.member.dao; import com.example.spring02.model.member.dto.MemberDTO; public interface MemberDAO { public String loginCheck(MemberDTO dto); //DTO에서 값을 받아 로그인을 체크하는 메소드 } | cs |
MemberDAOImpl.java (DB연결 구현 클래스) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | package com.example.spring02.model.member.dao; import javax.inject.Inject; import org.apache.ibatis.session.SqlSession; import org.springframework.stereotype.Repository; import com.example.spring02.model.member.dto.MemberDTO; @Repository public class MemberDAOImpl implements MemberDAO { //mybatis를 호출하기 때문에 Inject을 받아야한다 (의존성 주입) @Inject SqlSession sqlSession; @Override public String loginCheck(MemberDTO dto) { //loginCheck메소드를 구현 return sqlSession.selectOne("member.login_check", dto);
//sqlsession의 selectOne메소드에 한가지 값(dto)를 담아서 리턴함 //mapper을 호출하기 위해 mapper id와 저장할 값을 지정 } }
| cs |
memberMapper.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와 중복되지 않도록 네임스페이스 기재 -->
<mapper namespace="member">
<select id = "Login_check" resultType = "com.example.spring02.model.member.dto.MemberDTO"> <!-- id 속성에는 해당 sql문을 참조하는 이름 (파일)을 적고 => Login_check resultType는 검색결과의 레코드를 어떤 형태로 변환시킬건지 작성한다. -->
<!-- 즉 Login_check파일에서 밑에 있는 sql문을 참조하고 (실행하고) 그 결과를 MemberDTO 타입으로 변환 (다른 계층으로 자료를 이동시키기 위해) 한다. --> select * from member where userid = #{userid} and passwd = #{passwd} <!-- 회원의 아이디와 비밀번호가 모두 일치하는 회원의 모든 정보를 검색하는 sql문 -->
</select> </mapper> | cs |
MemberService.java (회원 서비스 인터페이스) | package com.example.spring02.service.member; import javax.servlet.http.HttpSession; import com.example.spring02.model.member.dto.MemberDTO; public interface MemberService { //HttpSession은 사용자 인증정보를 처리하는 클래스 public String loginCheck(MemberDTO dto, HttpSession session); //로그인 체크 메소드 public void logout(HttpSession session); //로그아웃 체크 메소드 } | cs |
MemberServiceImpl.java (회원 서비스 인터페이스 구현 클래스) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | package com.example.spring02.service.member; import javax.inject.Inject; import javax.servlet.http.HttpSession; import org.springframework.stereotype.Service; import com.example.spring02.model.member.dao.MemberDAO; import com.example.spring02.model.member.dto.MemberDTO; //서비스 계층에서 서비스를 처리하는 어노테이션이므로 서비스 어노테이션을 반드시 붙여야 한다. @Service public class MemberServiceImpl implements MemberService { // 서비스는 dao를 호출하기 때문에 의존성을 주입해야한다. @Inject MemberDAO memberDao; @Override public String loginCheck(MemberDTO dto, HttpSession session) { // 로그인 체크 메소드 // 그러니까 DTO => DAO 로 넘어가는 과정 // 아이디와 비밀번호가 맞으면 이름이 넘어오고 틀리면 null이 넘어온다. // dao 클래스에 로그인 체크 메소드에 매개값으로 주어진 이름을 name변수에 저장 String name = memberDao.loginCheck(dto); if (name != null) {// 맞으면 // 세션변수 등록 session.setAttribute("userid", dto.getUserid()); // DTO에 저장된 회원의 아이디를 userid라는 이름으로 세션에 저장 session.setAttribute("name", name); // 위에서 로그인체크를 할때 받은 name를 세션에 저장하고 이 이름을 name라고 저장한다. } return name; } @Override public void logout(HttpSession session) { // 세션을 모두 초기화시킴 (로그아웃이므로 세션에 저장된 회원정보를 없애야 한다.) // invalidate( )메소드를 사용하면 사용자의 id까지 바뀌어버린다. session.invalidate(); } } | cs |
MemberController.java (회원정보 컨트롤러) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | package com.example.spring02.controller.member; import javax.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import com.example.spring02.service.member.MemberService; @Controller @RequestMapping("/member/*") // 클래스 전체에서 사용하는 공통적인 url 매핑, 매핑을 할때 공통적인 코드를 줄이기 위해서 사용한다. public class MemberController { private static final Logger logger = LoggerFactory.getLogger(MemberController.class); // MemberController의 로그를 출력하기 위해 getLogger 메소드를 사용해서 LoggewrFactory 에 담고 logger 변수에 저장 // 컨트롤러에서 서비스를 호출하기 때문에 어노테이션을 사용해서 의존성을 주입해야한다. // 객체 생성과 소멸을 스프링에서 관리하게끔 하기 위해 @Inject MemberService memberService; @RequestMapping("login.do") // 이쪽에 있는건 세부적인 매핑 // login.do로 요청을 하면 member 폴더의 login.jsp 파일로 이동해서 로그인 할 수 있는 화면을 만들어주게끔 한다. public String login() { return "member/login"; } } | cs |
login.jsp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <%@ include file="../include/header.jsp"%> <script> //아래쪽에서 id값을 받아서 데이터를 전송한다. //click 메소드 안에 있는 함수를 실행해서 id와 비밀번호를 저장하고 //빈 값(공백값) 이면 경고창을 출력하고, 커서를 이동시킨다. // val () 메소드는 form (양식)의 값을 가져오거나 값을 설정하는 메소드 // focus () 메소드는 해당 요소에 포커스를 부여하고, 텍스트 창의 경우 커서를 위치시켜 바로 입력이 가능하도록 하던가 // 버튼의 경우, 엔터키를 눌렀을때 클릭 효과를 낸다. $(function(){ $("#btnLogin").click(function(){ var userid = $("#userid").val(); var passwd = $("#passwd").val(); if(userid==""){ alert("아이디를 입력하세요."); $("#userid").focus(); return; } if(passwd==""){ alert("비밀번호를 입력하세요."); $("#passwd").focus(); return; } //아이디와 비밀번호가 맞으면 login_check페이지로 넘어간다. document.form1.action = "${path}/member/login_check.do"; document.form1.submit(); }); }); </script> </head> <body> <%@ include file="../include/menu.jsp"%> <h2>로그인</h2> <form name="form1" method="post"> <table border="1" width="400px"> <tr> <td>아이디</td> <td><input id="userid" name="userid"></td> </tr> <tr> <td>비밀번호</td> <td><input type="password" id="passwd" name="passwd"></td> </tr> <tr> <td colspan="2" align="center"> <!-- type가 button타입이기 때문에 데이터 전송기능이 없다. --> <!-- 그래서 id값을 javascript에 줘서 자바스크립트에서 데이터를 전송할 수 있게끔 한다. --> <button type="button" id="btnLogin">로그인</button> <!-- param(파라미터)를 사용해서 값이 다시 넘어오는 경우 로그인이 안되어있으면 (nologin) --> <!-- 먼저 로그인 하라는 메시지를 출력한다. --> <c:if test="${param.message == 'nologin' }"> <div style="color: red;">먼저 로그인 하세요.</div> </c:if> <!-- param(파라미터)를 사용해서 값이 넘어오는 경우에 아이디와 비밀번호가 틀려서 'error'과 같으면 --> <!-- 아이디 또는 비밀번호가 일치하지 않는다는 메시지를 출력함 --> <c:if test="${param.message == 'error' }"> <div style="color: red;">아이디 또는 비밀번호가 일치하지 않습니다.</div> </c:if> <!-- 또한 로그아웃틀 하게되면 로그아웃이 되었다는 메시지를 출력함 --> <c:if test="${param.message == 'logout' }"> <div style="color: red;">로그아웃 되었습니다.</div> </c:if> </table> </form> </body> </html> | cs |
login 페이지에서 로그인 정보를 쓰고 로그인 버튼을 누르면 컨트롤러의 logincheck 로 넘어감.
MemberController.java 중 일부
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | //View (login 페이지에서 아이디와 비밀번호를 쓰게 되면 컨트롤러에서 이 메소드를 거쳐서 logincheck페이지로 이동함) @RequestMapping("login_check.do") public ModelAndView login_check(@ModelAttribute MemberDTO dto, HttpSession session) { //login페이지에서 넘어와서 DTO에 저장된 아이디와 비밀번호를 @ModeAttribute어노테이션을 사용해서 한꺼번에 2개를 다 받는다. //사용자가 로그인한 정보를 계속 가지고 있게 하기 위해서 세션도 받는다. //로그인 성공 => 이름이 넘어옴, 실패 => NULL이 넘어옴 String name = memberService.loginCheck(dto, session); //서비스 계층에 loginCheck메소드의 매개값으로 dto (아이디, 비밀번호, 세션) 변수 name에 저장 ModelAndView mav = new ModelAndView(); // 데이터를 보낼 뷰와 데이터를 동시에 설정하기 위해 ModelAndView타입의 객체를 생성한다. if (name != null) { //로그인이 성공하면 시작페이지로 이동함. mav.setViewName("home"); }else {//로그인이 실패하면 login 페이지로 다시 돌아감 mav.setViewName("member/login"); mav.addObject("message", "error"); //로그인 페이지에 에러라는 값을 준다. 그러면 그 에러메시지를 값으로 받아서 경고메시지 출력 } return mav; } | cs |
-로그아웃-
MemberController.java 중 일부 | @RequestMapping("logout.do") //logout.do에 매핑 public ModelAndView logout( HttpSession session, ModelAndView mav) { memberService.logout(session); //세션 초기화 작업 mav.setViewName("member/login"); //이동할 페이지의 이름 mav.addObject("message","logout"); //변수 저장 return mav; //페이지로 이동 } | cs |
login.jsp 중 일부 mav에 있는 logout 메시지가 아래 구문에서 걸려서 "로그아웃 되었습니다" 메시지를 출력한다. | <c:if test="${message == 'logout' }"> <div style="color:red;"> 로그아웃되었습니다. </div> </c:if> | cs |
Back-End/Spring 2019. 6. 12. 12:29
상품관리 (상품 상세 보기 구현)
상품이름에 링크를 걸어 상품 상세정보를 출력하고, 장바구니 기능을 사용할수있게 한다.
-상품 상세 보기-
1. list 파일에서 "상품상세보기" 링크를 클릭 하면 URL을 컨트롤러로 보낸다.
2. 그리고 끝에 들어가는 상품 번호는 URL에 포함된 변수이므로 @PathVariable로 저장이 된다.
3. list파일에서 보낸 URL을 컨트롤러에서 받고, 그 URL에 맞는 @RequestMapping된 메소드를 실행한다.
4. 매핑된 메소드 안에는 데이터를 보낼 뷰를 설정하고, 보낼 데이터를 동시에 설정하기 위해 ModelAndView 타입을 사용하고,
5. setViewName( ) 메소드 (데이터를 보낼 뷰의 위치) , addObject( ) 메소드 (보낼 데이터와 보낼 데이터의 이름을 지정) Product을 사용해 ModelAndView 타입으로 리턴한다. (즉, 상품번호를 리턴함)
6. DAO 구현 클래스에서 sqlsession의 selectone( ) 메소드를 사용해서 sqlsession에 저장된 값 중 하나 (상품번호) 를 리턴한다. (단, namespace와 id를 맞게 입력을 해야 mapper과 매핑이 되니 주의)
7. mapper에서 select id에 namespace 이름을 적고, 조건을 설정해서 sql구문을 사용하기 위해 id에 인터페이스에서 구현한 product_id (상품번호)를 넣는다.
1. product_list 중 일부 (상품 상세보기를 하기 위해 상품이름에 링크를 거는 코드 추가) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <tr> <th>상품ID</th> <th>상품사진</th> <th>상품명</th> <th>가격</th> </tr> <c:forEach var="row" items="${list }"> <tr align = "center"> <td>${row.product_id }</td> <td><img src="${path }/images/${row.picture_url}" width="100" height = "100"></td> <td> <a href = "${path }/shop/product/detail/${row.product_id}"> ${row.product_name }</a> //끝에 상품 코드가 들어간다. 그리고 끝에 들어가는 상품 번호는 //URL에 포함된 변수이므로 @PathVariable로 저장이 된다. </td> | cs |
이 URL을 컨트롤러로 받아서 처리
2. ProductController.java 중 일부 (url 매핑 처리 코드 추가) |
//상세정보 페이지에서 URL이 매핑되서 실행
@RequestMapping("/detail/{product_id}")
public ModelAndView detail(
//아까 product_list 페이지에서 보낸 id와, @PathVariable("product_id") //URL에 포함된 변수이기 때문에 반드시 @PathVariable를 사용한다.
int product_id, ModelAndView mav) {
//데이터를 보낼 뷰를 설정하고, 보낼 데이터를 동시에 설정하기 위해 ModelAndView를 사용 //ModelAndView에 데이터를 보낼 뷰의 위치를 설정하고, //보낼 데이터를 설정하고, ModelAndView타입으로 리턴한다.
mav.setViewName("/shop/product_detail"); mav.addObject("dto", productService.detailProduct(product_id));
return mav; }
| cs |
3. ProductServiceImpl.java (서비스 인터페이스 구현 클래스) 중 일부 | @Override public ProductDTO detailProduct(int product_id) { return productDao.detailProduct(product_id); //상품아이디를 매개변수로 받아서 Dao에 있는 상품의 정보를 리턴 } | cs |
4. ProductDAOImpl.java (DAO 인터페이스 구현 클래스) 중 일부 | @Override public ProductDTO detailProduct(int product_id) { return sqlSession.selectOne(//sqlsession에 저장된 값중에 하나를 리턴한다 (상품번호) "product.detail_product",product_id); //앞쪽에 namespace와 뒤쪽에 id를 적는다. 이렇게 해야 Mapper와 매핑이 된다. } | cs |
1. selectOne : 쿼리 결과가 없으면 null을 반환한다. 쿼리 결과로 레코드가 하나만 나와야 한다. DB에 레코드가 하나만 있는 경우에 사용 => 다수의 레코드가 있을 시 TooManyResultsException 에러가 발생
2. selectList : 쿼리 결과를 List<E>로 반환한다. 결과가 없을 시에는 빈 List를 반환한다 (null을 반환한다,)
|
5. productMapper.xml 중 일부
하나의 데이터가 DTO에 저장이 되서 계속 넘어가는 구조 | <select id = "detail_product" resultType = "com.example.spring02.model.shop.dto.ProductDTO" >
<!-- 상품 상세정보 확인 id -->
select * from product where product_id=#{product_id} //select id에 namespace 이름을 적고, 조건을 설정해서 sql구문을 사용하기 위해 </select> //id에 인터페이스에서 구현한 product_id (상품번호)를 넣는다. | cs |
6. product_detail.jsp 파일 작성 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <%@include file="../include/header.jsp"%> </head> <body> <%@ include file="../include/menu.jsp"%> <h2>상품 정보</h2> <table> <tr> <!-- 이미지를 불러오기위한 url 작성 --> <td><img src="${path}/images/${dto.picture_url}" width="300px" height="300px"></td> <td align="center"> <table> <tr> <td>상품명</td> <td>${dto.product_name }</td> </tr> <tr> <td>가격</td> <td>${dto.price }</td> </tr> <tr> <td> </td> <td>${dto.description }</td> <!-- 상품 설명을 가져옴 --> </tr> <tr> <td colspan="2"> * 장바구니에 담기 기능 *
<form name="form1" method="post" action="${path }/shop/cart/insert.do"> <input type="hidden" name="product_id" value="${dto.product_id }"> <!-- 상품코드를 히든타입으로 넘김 --> <select name="amount"> <c:forEach begin="1" end="10" var="i"> <option value="${i}">${i}</option> <!-- 장바구니에 10개 까지 담을수 있다.--> </c:forEach> </select> 개 <input type="submit" value="장바구니에 담기"> </form> <a href="${path}/shop/product/list.do">상품목록</a> </td> </tr> </table> </table> </body> </html> | cs |
Back-End/Spring 2019. 6. 12. 11:48
- 상품관리 실습 파일 목록 -
ProductDTO.java (계층별 데이터 이동)
ProductDAO.java (상품관리 DB연결 인터페이스)
ProductDAOImpl.java (상품관리 DB연결 구현 클래스)
ProductMapper.xml (SQL 매핑 어노테이션을 가진 자바 클래스)
ProductService.java (상품 서비스 계층 인터페이스)
ProductServiceImpl.java (상품 서비스 계층 구현 클래스)
product_list.jsp (상품 리스트)
product_detail.jsp (상품 정보)
|
기본적으로 컨트롤러 => 서비스 호출 서비스 => 모델 호출
참고 https://abn-abn.tistory.com/211
-상품 목록보기 구현-
1. 메인페이지에서 컨트롤러(list.do) URL이 매핑되어 있는 메소드를 호출
2. 그 메소드에서는 ProductService에서 상품 리스트를 받아와서 list라는 이름으로 저장하고, product_list페이지로 이동.
3. product_list 페이지에서는 ProductDAO (ProductDAOImpl로 구현한 클래스) 에서 DB에 저장된 ID, NAME, PRICE, PICTURE_URL 값을 DTO를 거쳐서 불러온다.
4. ProductMapper.xml에서 SQL 상품 정보를 정렬해주는 SQL문을 실행하고, 그 상품 정보(DTO에 담긴 정보)들을 arraylist에 저장한다.
5. product_list파일에선 그 저장한 리스트를 불러와서 하나씩 출력한다.
ProductDTO.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | package com.example.spring02.model.shop.dto; import org.springframework.web.multipart.MultipartFile; public class ProductDTO { private int product_id; private String product_name; private int price; private String description; private String picture_url; private MultipartFile file1; //첨부파일은 MultipartFile타입으로 저장한다. public int getProduct_id() { return product_id; } public void setProduct_id(int product_id) { this.product_id = product_id; } public String getProduct_name() { return product_name; } public void setProduct_name(String product_name) { this.product_name = product_name; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getPicture_url() { return picture_url; } public void setPrcture_url(String picture_url) { this.picture_url = picture_url; } public MultipartFile getFile1() { return file1; } public void setFile1(MultipartFile file1) { this.file1 = file1; } @Override public String toString() { return "ProductDTO [product_id=" + product_id + ", product_name=" + picture_name + ", price=" + price + ", description=" + description + ", prcture_url=" + picture_url + ", file1=" + file1 + "]"; } } | cs |
ProductDAO.java (DAO 인터페이스) | package com.example.spring02.model.shop.dao; import java.util.List; import com.example.spring02.model.shop.dto.ProductDTO; public interface ProductDAO { List<ProductDTO> listProduct(); ProductDTO detailProduct(int product_id); void updateProduct(ProductDTO dto); void deleteProduct(int product_id); void insertProduct(ProductDTO dto); String fileInfo(int product_id); }
| cs |
ProductDAOImpl.java 중 일부 (DAO 인터페이스 구현) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | package com.example.spring02.model.shop.dao; import java.util.List; import javax.inject.Inject; import org.apache.ibatis.session.SqlSession; import org.springframework.stereotype.Repository; import com.example.spring02.model.shop.dto.ProductDTO; @Repository //DB관련 객체를 스프링에서 대신 관리해주게하는 어노테이션 public class ProductDAOImpl implements ProductDAO { @Inject //sqlSession을 의존성을 주입해서 스프링 자체에서 객체를 생성하고 소멸시키게끔 한다. SqlSession sqlSession; @Override public List<ProductDTO> listProduct() { return sqlSession.selectList("product.list_product"); //mapper을 호출하게 한다.
"product.list_product"
product가 namespace의 이름
list_product가 id의 이름
productMapper.xml 파일과 맵핑 된다. (단, 맵핑 되려면 namespace이름과 id의 이름이 같아야함) } | cs |
root-context.xml (실행할 수있는 mapper의 경로가 작성되어 있다.) | <!-- SqlSessionFactory 객체 주입 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configLocation" value="classpath:/mybatis-config.xml"></property> <property name="mapperLocations" value="classpath:mappers/**/*Mapper.xml"></property> </bean> | cs |
productMapper.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?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와 중복되지 않도록 네임스페이스 기재 --> <!-- 목록을 뽑아야되므로 select SQL 구문을 추가한다. --> <mapper namespace="product"> <select id = "list_product" resultType = "com.example.spring02.model.shop.dto.ProductDTO"> <!-- 코드의 자료형을 알려준다 DTO타입으로 받아야 되므로 DTO파일의 경로를 입력. --> <!-- 이 코드가 호출되면 ProductDTO가 arraylist로 저장됨 --> select * from product order by product_id <!-- id의 내림차순으로 검색한다. (id의 오름차순으로 검색 - 1,2,3,4,.....10) --> </select> </mapper> | cs |
ProductService.java | package com.example.spring02.service.shop; import java.util.List; import com.example.spring02.model.shop.dto.ProductDTO; public interface ProductService { List<ProductDTO> listProduct(); ProductDTO detailProduct(int product_id); String fileInfo(int product_id); void updateProduct(ProductDTO dto); void deleteProduct(int product_id); void insertProduct(ProductDTO dto); } | cs |
ProductServiceImpl.java 중 일부 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | package com.example.spring02.service.shop; import java.util.List; import javax.inject.Inject; import org.springframework.stereotype.Service; import com.example.spring02.model.shop.dao.ProductDAO; import com.example.spring02.model.shop.dto.ProductDTO; @Service public class ProductServiceImpl implements ProductService { //Service에서는 model(DAO)를 받으므로 의존성을 주입해야한다. @Inject ProductDAO productDao; @Override public List<ProductDTO> listProduct() { return productDao.listProduct(); //데이터베이스에 저장된 상품 리스트를 리턴한다. }
| cs |
ProductController.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | package com.example.spring02.controller.shop; import javax.inject.Inject; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.example.spring02.service.shop.ProductService; @Controller //현재 클래스를 스프링에서 관리하는 Controller Bean으로 설정함 @RequestMapping("/shop/product/*") //공통적인 url 맵핑 public class ProductController { @Inject //의존관계 주입 (DI) ProductService productService; //스프링에서 만든 서비스 객체를 연결시킴 @RequestMapping("list.do") //세부적인 url mapping public ModelAndView list(ModelAndView mav) { mav.setViewName("/shop/product_list"); //이동할 페이지 이름 (product_list.jsp 파일로 이동) mav.addObject("list", productService.listProduct()); //데이터 저장 //서비스에서 상품 리스트를 받아와 list라는 이름의 변수에 저장 //service -> model -> mybatis -> 리스트를 받아옴 return mav; //페이지 이동 } } | cs |
menu.jsp (상품목록으로 이동하는 하이퍼링크 추가) | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %>
<!-- 다른페이지에 include되는 페이지 -->
<a href = "${path }/memo/list.do">한줄메모장</a> ㅣ <a href = "${path }/upload/uploadForm">업로드 테스트</a> ㅣ <a href = "${path }/shop/product_list.do">상품목록</a> ㅣ
| cs |
product_list.jsp (상품리스트 출력 jsp 파일) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv = "Content=Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> <%@ include file = "../include/header.jsp" %> <script>
$(function(){ //자바스크립트 태그안쪽에 $("#btnAdd").click(function(){ location.href = "${path}/shop/product/write.do"; }); });
</script> </head> <body> <%@ include file = "../include/menu.jsp" %> <h2>상품목록</h2> <button type = "button" id = "btnAdd">상품등록</button> <table border = "1" width = "500px"> <tr> <th>상품ID</th> <th>상품사진</th> <th>상품명</th> <th>가격</th> </tr> <c:forEach var="row" items="${list }"> //컨트롤러의 list변수와 같다. <tr align = "center"> <td>${row.product_id }</td> <td><img src="${path }/images/${row.picture_url}" width="100" height = "100"></td> <td>${row.product_name }</td> <td> <fmt:formatNumber value="${row.price}" pattern="#,###" /> </td> <!-- 가격을 표시하기 위해서 사용함. 0이 3개 있을 때마다 ,를 하나씩 찍게 한다. --> </tr> </c:forEach> </table> </body> </html> | cs |
Back-End/Spring 2019. 6. 11. 13:36
-파일업로드 방식의 종류-
1. 일반적인 방식 (여기서는 일반적인 방식으로 테스트)
2. 비동기적인 방식 (ajax)
1. 상품 정보를 저장할 테이블 만들기
| create table product( product_id number, product_name varchar2(50), price number default 0, description clob, picture_url varchar2(500), //varchar2는 4000바이트 까지밖에 들어가지 않는다. primary key(product_id) ); | cs |
clob : 사이즈가 큰 데이터를 외부 파일로 저장하기 위한 데이터 타입
default : 기본값 설정 (예를들어 default 0 이면 기본값이 0부터 시작한다. 기본 번호가 0부터 시작하고 증가하는 식으로 생각하면 편함)
만든 테이블에 자료를 삽입한다.
| insert into product values (1,'레몬',1500,'레몬에 포함된 구연산은 피로회복에 좋습니다. 비타민 C도 풍부합니다,','lemon.jpg'); insert into product values (2,'오렌지',2000,'비타민 C가 풍부합니다. 생과일 주스로 마시면 좋습니다.','orange.jpg'); insert into product values (3,'키위',3000,'비타민 C가 매우 풍부합니다. 다이어트나 미용에 좋습니다.','kiwi.jpg'); insert into product values (4,'포도',5000,'폴리페놀을 다량 함유하고 있어 항산화 작용을 합니다.','grape.jpg'); insert into product values (5,'딸기',8000,'비타민 C나 플라보노이드를 다량 함유하고 있습니다.','strawberry.jpg'); insert into product values (6,'귤',7000,'시네피린을 함유하고 있어 감기 예방에 좋다고 합니다.','tangerine.jpg'); | cs |
자료를 삽입한후 삽입한 자료가 반영되도록 커밋을 실시한다.
상품이 등록될때마다 넘버를 증가시키기위해 시퀀스를 생성
(처음 시작은 10부터 하고, 1씩 증가시키는 시퀀스를 생성한다.)
| create sequence seq_product start with 10 increment by 1; | cs |
insert로 아래 값을 삽입한다. seq_product.nextval은 아까 10번부터 시작한다고 설정해 놓았으므로 10으로 설정됨 다음에 다시 사용한다면 11이 된다.
| insert into product values (seq_product.nextval, '사과',1500,'맛있는 사과...','apple.jpg'); | cs |
2. 상품 이미지를 다운로드하여 views/images 디렉토리에 복사 ( http://mannaedu.com/bbs/board.php?bo_table=pds&wr_id=37&page=3 )
3. pom.xml (라이브러리 추가) ( https://mvnrepository.com ) groupID와 artifactID를 이용해서 파일업로드와 이미지 썸네일 관련 라이브러리를 검색해서 추가한다.
![](https://t1.daumcdn.net/cfile/tistory/99675F375CFE200D20)
pom.xml (라이브러리들 추가) | <!-- 파일업로드 관련 라이브러리 --> <dependency> <groupld>commons-fileupload</groupld> <artifactld>commons-fileupload</artifactld> <version>1.3.3</version> </dependency> <!-- 이미지 썸네일을 만들어주는 라이브러리 --> <dependency> <groupld>org.imgscalr</groupld> <artifactId>imgscalr-lib</artifactId> <version>4.2</version> </dependency> | cs |
4. views 하위에 images 폴더를 만들고 아까 다운받은 상품 이미지를 폴더에 넣기
5.servlet-context에서 images파일의 리소스를 맵핑 할수 있도록 코드를 추가한다.
| <resources location="/WEB-INF/views/images/" mapping= "images/**" /> | cs |
6. servlet-context.xml (파일업로드 관련 설정) 코드 추가 |
<!-- 파일업로드에 필요한 bean --> <beans:bean id = "multipartResolver" //스프링 프레임 워크에 내장된 빈을 추가함 class = "org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 파일 업로드 최대 용량(byte단위로) --> <beans:property name = "maxUploadSize" value = "10485760" /> //value에 최대 용량 설정함 </beans:bean>
<!-- 파일 업로드를 위한 디렉토리 설정 --> <!-- String uploadPath = new String("d:/upload"); --> <beans:bean id = "uploadPath" class = "java.lang.String"> <beans:constructor-arg value = "d:/upload" /> //파일이 업로드 되는 디렉토리는 d:/upload 이다. </beans:bean>
| cs |
7. menu.jsp 업로드 테스트 링크를 추가함. | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %> <!-- 다른페이지에 include되는 페이지 --> <a href = "${path }/memo/list.do">한줄메모장</a> ㅣ <a href = "${path }/upload/uploadForm">업로드 테스트</a> ㅣ //업로드 테스트 링크를 추가 | cs |
8. controller 패키지 하위에 upload 패키지를 만들고 UploadController.java 클래스를 추가함 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | package com.example.spring02.controller.upload; import java.io.File; import java.util.UUID; import javax.annotation.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.util.FileCopyUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.ModelAndView; @Controller public class UploadController { private static final Logger logger = LoggerFactory.getLogger(UploadController.class); //이 클래스의 로그를 출력하기 위한 코드, 로그저장소에서 getLogger 메소드를 사용해서 호출 // xml에 설정된 리소스를 참조 // bean의 id가 uploadPath인 태그를 참조 @Resource(name = "uploadPath") //servlet-conetext에 저장한 빈인 uploadPath를 호출한다. String uploadPath; //@Resource에서 받은 리소스 값인 uploadPath가 들어오게 된다. // menu 페이지에서 이 메소드를 거치고, 맵핑할때 "/upload/uploadForm"페이지로 포워딩 된다. // method방식을 정하지 않으면 get방식이다. (즉 get방식일때는 이 메소드를 거친다. post방식일때는 아님) @RequestMapping(value = "/upload/uploadForm", method = RequestMethod.GET) public void uploadForm() { // upload / uploadForm.jsp 로 포워딩 } //그냥 화면을 바꿀때는 get 방식을 사용하고 파일을 업로드 할때는 POST방식을 사용한다. //업로드 버튼 => 임시 디렉토리에 업로드 // => 파일정보가 file에 저장 // => 지정된 디렉토리에 저장 => // 파일을 업로드(내용을 채울때는) 할때는 POST방식을 사용하므로 이 메소드를 거친다. // 메소드 이름을 다르게 할 수도 있지만 method 방식을 POST와 GET방식으로 각각 지정해서 할 수도 있다. @RequestMapping(value = "/upload/uploadForm", method = RequestMethod.POST) public ModelAndView uploadForm (MultipartFile file, ModelAndView mav) throws Exception { logger.info("파일이름 : " + file.getOriginalFilename()); String savedName = file.getOriginalFilename(); logger.info("파일크기:" +file.getSize()); logger.info("컨텐츠 타입:" +file.getContentType()); //파일이름과 크기와 파일의 종류를 로그로 출력함 savedName = uploadFile(savedName, file.getBytes()); //파일을 올리고 파일의 바이트를 올리고, 저장된 파일이름 가져와서 결과페이로 보낼예정 mav.setViewName("upload/uploadResult"); mav.addObject("savedName", savedName); return mav; //uploadResult.jsp로 포워딩 } //파일 이름이 중복되지 않도록 처리 private String uploadFile(String originalName, byte[] fileData) throws Exception{ // uuid 생성 (Universal Unique IDentifier, 범용 고유 식별자) // uuid를 만드는 이유는 파일을 2개 올리게 되면 이름이 중복되는데 그러다 1개가 삭제 될 수 있기 때문에 // uuid라는 고유한 식별자를 주어서 (랜덤으로 코드를 만들어냄) 이름이 중복되지 않게 해서 삭제되지 않게끔 하려는 것이다. // uuid를 생성해서 그것을 파일의 이름 앞에다 붙여서 중복을 방지한다. UUID uid = UUID.randomUUID(); String savedName = uid.toString() + "_" +originalName; File targer = new File(uploadPath, savedName); //파일을 실제로 저장함 // 임시 디렉토리에 저장된 업로드된 파일을 // 지정된 디렉토리로 복사 // FileCopyUtils.copy (바이트배열, 파일객체) FileCopyUtils.copy(fileData, targer); //파일을 복사 return savedName; //복사한 파일이름을 되돌려 준다. } } | cs |
9. views에 upload폴더를 만들고, uploadForm.jsp 파일을 만든다. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv = "Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> <%@ include file = "../include/header.jsp" %> <style> iframe{ width : 400px; height : 200px; border : 1px; border-style : solid; } </style> </head> <body> <%@ include file = "../include/menu.jsp" %> <!-- enctype = "multipart/form-data" 파일 업로드 필수 옵션 enctype = "application/x-www-form-urlencoded" 기본 옵션--> <!-- target = "iframe" 의 name => iframe으로 전송함 --> <form id = "form1" action = "${path }/upload/uploadForm" method = "post" enctype = "multipart/form-data"
target = "iframe1" > //파일을 업로드 하게 되면 원래 ${path }/upload/uploadForm 경로로 가게 되는데 현재 화면에서 //화면이 넘어가지 않게 해준다. (즉, iframe1페이지에 고정됨)
<input type = "file" name = "file"> //name의 파일이름 file와 UploadController에서 이 페이지를 맵핑받은 메소드의 //MultipartFile 타입의 변수 이름이 같아야 저장이 된다.
<input type = "submit" value = "업로드"> </form> <iframe name="iframe1"></iframe> </body> </html> | cs |
10. views폴더 하위에 upload 폴더 안에 uploadResult.jsp 파일을 추가한다. | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv = "Content-Type" content = "text/html; charset=UTF-8"> <title>Insert title here</title> <%@ include file = "../include/header.jsp" %> </head> <body> <%@ include file = "../include/menu.jsp" %> <!-- uploadResult.jsp --> 파일이 업로드 되었습니다. <br> 파일명 : ${savedName } //그리고 이 파일이 uploadForm의 iframe로 들어간다. </body> </html> | cs |
11. D드라이브에 업로드된 파일이 들어갈 upload 폴더 만들기
Back-End/Spring 2019. 6. 10. 11:32
MemoService.java : dao에 값만 전달해 주는 역할
-글 수정 구현-
글 상세보기 (View.java) 페이지 에서 시작
=> 수정 버튼 클릭 (글 수정을 위해 dto.idx (글번호) 를 매개변수로 넘기고, 마찬가지로 id값인 btnUpdate도 넘긴다.)
=> view 파일 상부에 있는 javascript 구문 실행 (id을 $("")으로 받고, dto.idx (dto에 있는 글번호 값)도 $("")로 받는다.) 그리고, 함수(function)을 실행한다.
=> 받은 dto.idx(글번호 값을) controller에 넘긴다 (왜냐하면 그 쪽에 @RequestMapping으로 url이 맵핑되어 있기 때문에)
=> controller 안에 있는 메소드인 update메소드에 @PathVariable int idx (글번호)와 수정을 해야하기 때문에 MemoDTO dto (이름값과 메모값이 담겨있음) 를 매개변수로 받는다.
=> update 메소드 안에 있는 memoService.update메소드 (memoServiceImpl.java 에서 구현되어 있음)를 실행한다. (이 update메소드는 DAO에서 @Update 어노테이션을 사용해서 쿼리문이 대입된 상태이다.
=> update 메소드에 있는 쿼리가 정상적으로 실행이 되면 글수정을 해서 최신화를 하고 list.do 페이지로 돌아가게 된다.
-글 삭제 구현-
글 삭제 (View.java) 페이지 에서 시작
=> 삭제 버튼 클릭 (글 삭제를 위해 dto.idx (글번호) 를 매개변수로 넘기고, 마찬가지로 id값인 btnDelete도 넘긴다.)
=> view 파일 상부에 있는 javascript 구문 실행 (id을 $("")으로 받고, dto.idx(dto에 있는 글번호 값)도 $("")로 받는다.) 그리고, 함수(function)을 실행한다.
=> 받은 dto.idx(글번호 값을) controller에 넘긴다. (왜냐하면 그 쪽에 @RequestMapping으로 맵핑되어 있기 때문에)
=> controller 안에 있는 메소드인 delete메소드에 @PathVariable int idx (글번호)를 넘긴다.
=> delete 메소드 안에 있는 memoService.delete (memoServiceImpl.java에서 구현되어 있음) 메소드를 실행한다. (이 delete 메소드는 DAO에서 @Delete 어노테이션을 사용해서 쿼리문이 대입된 상태이다.
=> delete 메소드에 있는 쿼리가 정상적으로 실행이 되면 최신화를 하고 list.do 페이지로 돌아가게 된다.
view.jsp중 일부
| <tr align = "center"> <td colspan = "2"> <input type = "hidden" name = "idx" value = "${dto.idx }"> <!--글 수정을 하기 위해 글번호를 hidden 타입의 매개변수로 넘긴다. --> <button type = "button" id = "btnUpdate">수정</button> <button type = "button" id = "btnDelete">삭제</button> <!-- button type을빼면 무조건 재출력버튼이 되기 때문에 타입을 button으로 한다. --> </td> </tr> | cs |
| <script> $(function() {//밑에서 작성한 id값이 넘어오면 click메소드 안에 들어있는 function()함수를 실행해서 //수정하거나 삭제할때 각각 번호를 넘겨서 삭제한다. $("#btnUpdate").click(function(){//수정버튼을 누르면 밑에서 사용한 id값이 넘어오고 function()메소드를 실행해서 //dto의 글번호 값을 넘겨준다. document.form1.action="${path}/memo/update/${dto.idx}"; document.form1.submit(); }); $("#btnDelete").click(function(){ //삭제 버튼을 누르면 confirm메소드를 실행해서 확인창을 띄우고, dto의 글번호값을 넘겨준다. if(confirm("삭제하시겠습니까?")){ location.href="${path}/memo/delete/${dto.idx}"; } }); }); </script> | cs |
MemoController.java 중 일부
| @RequestMapping("update/{idx}") public String update(@PathVariable int idx, MemoDTO dto) { memoService.update(dto); return "redirect:/memo/list.do"; } @RequestMapping("delete/{idx}") public String delete(@PathVariable int idx) { memoService.delete(idx); return "redirect:/memo/list.do"; }
| cs |
MemoDAO.java 중 일부
| @Update("update memo set writer=#{writer}, memo=#{memo} " + "where idx=#{idx}") public void memo_update (MemoDTO dto); //글번호를 매개변수로 받고 @Param을 사용하면 괄호 안에 값이 쿼리문의 #안쪽에 대입이된다. @Delete("delete memo where idx=#{idx}") public void memo_delete(@Param("idx") int idx); //글번호를 매개변수로 받고 @Param을 사용하면 괄호 안에 값이 쿼리문의 #안쪽에 대입이된다. | cs |
MemoService.java (인터페이스) 중 일부
| public void update(MemoDTO dto);//수정 public void delete(int idx);//삭제 | cs |
MemoServiceImpl.java (인터페이스 구현 클래스) 중 일부
| @Override public void update(MemoDTO dto) { memoDao.memo_update(dto); //memoDAO의 update 메소드를 실행 } @Override public void delete(int idx) { memoDao.memo_delete(idx); //memoDAO의 delete 메소드를 실행 } | cs |
|