부트캠프83일차(회원정보수정, idpw찾기 , 장바구니)
1) 회원정보수정(update)
2) 회원탈퇴 (delete)
3) 비밀번호변경(password)
4) 아이디 , 비번 찾기
5) 장바구니(추가 동작만 실제반영X)
1) 회원정보수정 (update)
@PostMapping("update")
public ModelAndView idCheckUpdate(@Valid User user,BindingResult bresult,
String userid,HttpSession session) {
ModelAndView mav = new ModelAndView();
//입력값오류발생 시
if(bresult.hasErrors()) {
bresult.reject("error.update.user");
return mav;
}
User loginUser = (User)session.getAttribute("loginUser");
if(!loginUser.getPassword().equals(user.getPassword())) {
bresult.reject("error.login.password");
return mav;
}
//비밀번호일치시 실행
try {
service.userUpdate(user);
if(loginUser.getUserid().equals(user.getUserid())){
//세션을 수정된 데이터로변경
session.setAttribute("loginUser", user);
}
mav.setViewName("redirect:mypage?userid="+user.getUserid());
}catch (Exception e) {
e.printStackTrace();
throw new ShopException("고객정보수정실패", "update?userid="+user.getUserid());
}
return mav;
}
다음과같이 코드를 짜준다
중요한점이라고 볼 수 있는곳은 update가 완료된 이후에
session정보(user객체)를 변경된 정보로 다시 설정해주는 것
globalError를 추가해줘야함!!!
message.properties
error.update.user = 회원정보 수정 시 입력오류입니다.
error.login.password = 비밀번호가 틀려요
update.jsp의 일부분
<form:form modelAttribute="user" method="post" action="update">
<%--BindingResult.reject(코드값)으로 등록된 데이터들 조회 --%>
<spring:hasBindErrors name="user">
<font color="red"> <c:forEach items="${errors.globalErrors}"
var="error">
<!-- mvcConfig의 messageSource에 등록된 properties에서 코드값을 출력 -->
<spring:message code="${error.code}" />
<br>
</c:forEach>
</font>
</spring:hasBindErrors>
다음과같은 부분에 오류가 나타나게될것임
service, dao , mapper는
단순히 update를 하는
쿼리로이루어져있기때문에 생략하겠음!!!
2) 회원탈퇴 (delete)
1.관리자인경우 탈퇴불가능
* 2. 비밀번호검증 -> 로그인된비밀번호와비교
* 본인탈퇴시 : 본인비번
* 관리자 ->타인 탈퇴 : 관리자비번으로검증
* 3.비밀번호불일치
* 메시지출력후 delete페이지로이동
* 4.비밀번호일치
* db에서 사용자정보삭제
* 본인탈퇴 : 로그아웃 . login페이지로이동
* 관리자 타인 탈퇴 : admin/list 페이지이동
@PostMapping("delete")
public ModelAndView idCheckDelete(String password,String userid,HttpSession session) {
ModelAndView mav = new ModelAndView();
if(userid.equals("admin")) {
throw new ShopException("관리자는 탈퇴할수없어요", "mypage?userid="+userid);
}
User loginUser = (User)session.getAttribute("loginUser");
if(!password.equals(loginUser.getPassword())) {
throw new ShopException("비밀번호오류", "delete?userid="+userid);
}
try {
service.userDelete(userid);
}
catch (Exception e) {
e.printStackTrace();
throw new ShopException("탈퇴시 오류발생", "delete?userid="+userid);
}
//탈퇴성공
String url = null;
if(loginUser.getUserid().equals("admin")) {
url="redirect:../admin/list";
}
else {
session.invalidate();
url="redirect:login";
}
mav.setViewName(url);
return mav;
}
ModelandView.setViewName을 할 때
redirect를 해주지않는다면 jsp를 찾아가게될것임
하지만 redirect를 해준다면 해당 url정보에맞는 컨트롤러를 찾아갈거임
3) 비밀번호변경(password)
* 본인비번만 변경가능
* 1.로그인검증 -> AOP
* UserLoginAspect.loginCheck()
* poincut : UserController.loginCheck*(..)인 메서드,
* 마지막변수가 HttpSession인 메서드
* advice : around
* 2. 현재 DB의 비밀번호와 파라미터 현재비밀번호일치 검증
* 3.비밀번호일치 : DB수정 , 로그인정보변경 , mypage로이동
* 4.비밀번호 불일치 : 오류메시지 출력 후 password창으로!
@GetMapping("password")
public String loginCheckForm(HttpSession session) {
return null; //null로설정시 알아서 url을 맞춰줄거임
}
@PostMapping("password")
public ModelAndView loginCheckPassword(@RequestParam String password ,
@RequestParam String chgpass,HttpSession session) {
ModelAndView mav = new ModelAndView();
User loginUser = (User)session.getAttribute("loginUser");
//User user = service.selectUser(loginUser.getUserid());
if(!loginUser.getPassword().equals(password)) {
throw new ShopException("비밀번호 불일치", "password");
}
try {
loginUser.setPassword(chgpass);
service.changePw(loginUser);
session.setAttribute("loginUser", loginUser);
mav.setViewName("redirect:mypage?userid="+loginUser.getUserid());
return mav;
}
catch (Exception e) {
e.printStackTrace();
throw new ShopException("비밀번호변경시 DB오류입니다", "password");
}
}
post방식으로 파라미터값들이 넘어오므로 자기자신만 접근이가능함
일단 loginCheck AOP를 설정해보자 ( 로그인검증만 있으면 됨)
aop / UserLoginAspect.java
@Around("execution(* controller.User*.loginCheck*(..)) && args(..,session)")
public Object loginCheck(ProceedingJoinPoint joinPoint,
HttpSession session) throws Throwable{
User loginUser = (User)session.getAttribute("loginUser");
if(loginUser==null || !(loginUser instanceof User)) {
throw new ShopException("[loginChk]로그인 필요", "login");
}
return joinPoint.proceed();
}
4) 아이디 , 비번 찾기
(굉장히 복잡하고 어려운로직임 설명을 몇개달아놓긴 할거임)
일단 mapping방식이 특이하다 (잘안쓸것같음)pwSearch , idSearch매핑을 처리하는부분인데.!{url}Search 의 방식으로 받음
@Pathvariable을 이용해서 (pw or id)정보를 받아옴
@PostMapping("{url}Search")
public ModelAndView search(@ModelAttribute User user , BindingResult bresult,
@PathVariable String url) {
System.out.println("@@url : "+url+"@@");
//@PathVariable : {url}의 값을 매개변수로 전달
//idSearch 요청 : url = id
ModelAndView mav = new ModelAndView();
String code = "error.userid.search";
String title = "아이디";
//요청url이 pwSearch라면 (아이디를 입력받을것임)
if(url.equals("pw")) {
title="비밀번호 초기화";
code="error.password.search";
if(user.getUserid()==null ||
user.getUserid().trim().equals("")) {
bresult.rejectValue("userid", "error.required");
}
}
//
if(user.getEmail()==null || user.getEmail().trim().equals("")) {
bresult.rejectValue("email", "error.required");
}
if(user.getPhoneno()==null || user.getPhoneno().trim().equals("")) {
bresult.rejectValue("phoneno", "error.required");
}
if(bresult.hasErrors()) {
bresult.reject("error.input.check");
return mav;
}
if(user.getUserid()!=null && user.getUserid().trim().equals("")) {
//modelAttribute로넘겨받은 user의 아이디값이 빈 값이라면?(idSearch에서넘어온경우)
user.setUserid(null);
}
String result = service.getSearch(user);
System.out.println("result : "+result);
if(result==null) {
bresult.reject(code);
return mav;
}
//url정보가 pw면 무작위비밀번호로업데이트 후 보여준다
if(url.equals("pw")) {
String tempPw = getTempPw();
user.setPassword(tempPw);
service.changePw(user);
result = user.getPassword();
}
mav.addObject("result",result);
mav.addObject("title",title);
mav.setViewName("search");
return mav;
}
getTempPw메서드 : 대소문자,숫자조합의 랜덤한 6자리문자생성
service.changePw : user객체의 id에 해당하는 비밀번호를 업데이트
DAO
public String search(User user) {
String col = "userid"; //아이디검색
if(user.getUserid()!=null) {
col = "password";//비밀번호검색
}
param.clear();
param.put("col", col);
param.put("userid", user.getUserid());
param.put("email", user.getEmail());
param.put("phoneno", user.getPhoneno());
return template.getMapper(cls).search(param);
}
Mapper
v@Select({"<script>",
"select ${col} from useraccount "
+ "where email=#{email} and phoneno=#{phoneno} "
+ "<if test='userid != null'> and userid=#{userid}</if> "
+ "</script>"})
String search(Map<String, Object> param);
5) 장바구니(추가 동작만 실제반영X)
controller(modelAndView에 적어준 url은 jsp주소를 이야기함)
cartAdd로 매핑이 되어있지만
실제로는 cart를 찾아감
package controller;
@Controller
@RequestMapping("cart")
public class CartController {
@Autowired
private ShopService service;
@RequestMapping("cartAdd")
public ModelAndView add(Integer id , Integer quantity,HttpSession session) {
//new ModelAndView(뷰명) : /WEB-INF/view/cart/cart.jsp
ModelAndView mav = new ModelAndView("cart/cart");
Item item = service.getItem(id);
Cart cart = (Cart)session.getAttribute("CART");
if(cart==null) {
cart = new Cart();
session.setAttribute("CART", cart);
}
List<ItemSet> list = cart.getItemSetList();
for (int i = 0; i < list.size(); i++) {
//같은 아이템이존재한다면 갯수만늘려주는 작업
if(list.get(i).getItem().equals(item)) {
quantity += list.get(i).getQuantity();
list.remove(i);
}
}
cart.push(new ItemSet(item, quantity));
mav.addObject("message",item.getName()+":"+quantity+"개 장바구니 추가");
mav.addObject("cart",cart);
System.out.println(cart);
return mav;
}
}
logic/ItemSet.java
package logic;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
@AllArgsConstructor //모든필드를 사용한 생성자
public class ItemSet {
private Item item;
private Integer quantity;
}
logic/cart.java
package logic;
@ToString
public class Cart {
private List<ItemSet> itemSetList = new ArrayList<ItemSet>();
public List<ItemSet> getItemSetList(){
return itemSetList;
}
public void push(ItemSet set) {
itemSetList.add(set);
}
public int getTotal() {
return itemSetList.stream()
//getItem().getPrice : item객체의 price프로퍼티
.mapToInt(s->s.getItem().getPrice() * s.getQuantity())
.sum();
}
}
cart.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>장바구니</title>
<!-- Bootstrap CSS CDN -->
</head>
<body>
<div class="cart-container">
<h2 class="text-center mb-4">장바구니</h2>
<table class="table table-striped table-hover">
<thead class="table-dark">
<tr>
<th colspan="4">장바구니 상품목록</th>
</tr>
<tr>
<th>상품명</th>
<th>가격</th>
<th>수량</th>
<th>합계</th>
</tr>
</thead>
<tbody>
<c:forEach items="${cart.itemSetList}" var="set" varStatus="stat">
<tr>
<td>${set.item.name}</td>
<td><fmt:formatNumber value="${set.item.price}" pattern="###,###"/></td>
<td><fmt:formatNumber value="${set.quantity}" pattern="###,###"/></td>
<td>
<fmt:formatNumber value="${set.quantity * set.item.price}" pattern="###,###"/>
<a href="cartDelete?index=${stat.index}" class="delete-btn">ⓧ</a>
</td>
</tr>
</c:forEach>
<tr class="total-row">
<td colspan="4" class="text-end">
총 구입 금액: <fmt:formatNumber value="${cart.total}" pattern="###,###"/>원
</td>
</tr>
</tbody>
</table>
<div class="message">
${message}
</div>
<div class="action-links">
<a href="../item/list" class="btn-shop">상품목록</a>
<a href="checkout" class="btn-checkout">주문하기</a>
</div>
</div>
<!-- Bootstrap JS and Popper.js CDN for interactive components -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</body>
</html>