일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- TodayILearned
- springaop
- 자바스크립트
- PWA
- js
- Oracle
- 메이븐
- 스프링
- HTML
- SpringMVC
- web
- sql
- sqldeveloper
- 자바프로그래밍
- mybatis
- 프레임워크
- 프로그레시브웹앱
- maven
- CSS
- framework
- javascript
- javaprogramming
- 생활코딩
- 오라클
- TIL
- JavaScript 내장객체
- progressive web app
- tdd
- 국비지원
- 서브쿼리
- Today
- Total
1cm
자바 프로그래밍_Day_110_회원 정보 수정, 회원 탈퇴 본문
2022. 01. 20
- 회원 정보 수정
> myPage.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<c:set var="path" value="${ pageContext.request.contextPath }"/>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>회원 정보 수정</h2>
<div id="view-container">
<form id="memberFrm" action="${ path }/member/update" method="post">
<table>
<tr>
<th>아이디</th>
<td>
<input type="text" name="userId" id="newId"
value="${ loginMember.id }" readonly required >
</td>
</tr>
<tr>
<th>이름</th>
<td>
<input type="text" name="userName" id="userName"
value="${ loginMember.name }" required>
</td>
</tr>
<tr>
<th>휴대폰</th>
<td>
<input type="tel" placeholder="(-없이)01012345678" name="phone" id="phone"
value="${ loginMember.phone }" maxlength="11">
</td>
</tr>
<tr>
<th>이메일</th>
<td>
<input type="email" placeholder="abc@abc.com" name="email" id="email"
value="${ loginMember.email }">
</td>
</tr>
<tr>
<th>주소</th>
<td>
<input type="text" name="address" id="address"
value="${ loginMember.address }">
</td>
</tr>
<tr>
<th>취미</th>
<td>
<label><input type="checkbox" name="hobby" id="hobby0"
value="운동" ${ fn:contains(loginMember.hobby, '운동') ? 'checked' : '' }>운동</label>
<label><input type="checkbox" name="hobby" id="hobby1"
value="등산" ${ fn:contains(loginMember.hobby, '등산') ? 'checked' : '' }>등산</label>
<label><input type="checkbox" name="hobby" id="hobby2"
value="독서" ${ fn:contains(loginMember.hobby, '독서') ? 'checked' : '' }>독서</label>
<label><input type="checkbox" name="hobby" id="hobby3"
value="게임" ${ fn:contains(loginMember.hobby, '게임') ? 'checked' : '' }>게임</label>
<label><input type="checkbox" name="hobby" id="hobby4"
value="여행" ${ fn:contains(loginMember.hobby, '여행') ? 'checked' : '' }>여행</label>
</td>
</tr>
</table>
<button type="button" id="updatePwd">비밀번호변경</button>
<input type="submit" value="정보수정">
<input type="button" id="btnDelete" value="탈퇴">
</form>
</div>
<script>
$(document).ready(() => {
$("#updatePwd").on("click", () => {
const url = "${ pageContext.request.contextPath }/member/updatePwd";
const status = "left=500px,top=200px,width=400px,height=200px";
open(url, "", status);
});
$("#btnDelete").on("click", () => {
if(confirm("정말로 탈퇴하시겠습니까?")) {
location.replace("${ pageContext.request.contextPath }/member/delete");
}
});
});
</script>
</body>
</html>
URL 주소를 입력, <a> -> GET요청
> MemberController.java
@GetMapping("/member/myPage")
public String myPage() {
return "member/myPage";
}
myPage -> 로그인 후에 페이지를 들어갈 수 있게 하기, 미로그인 시 접근 못하도록 처리하기
> home.jsp
<c:if test="${ !empty loginMember }">
<a href="${ path }/member/myPage">
${ loginMember.name }
</a>님, 안녕하세요.
<form action="${ path }/logout" method="post">
<button type="submit">로그아웃</button>
</form>
</c:if>
로그인 후 Anchor태그 사용해서 myPage 페이지로 이동
- 로그아웃 후 접근 시 메세지 출력 후 home으로 이동시키기
참고 : https://goddaehee.tistory.com/154
[Spring] Filter, Interceptor, AOP 차이 및 정리
[Spring] Filter, Interceptor, AOP 차이 및 정리 안녕하세요. 갓대희 입니다. 이번 포스팅은 [ [Spring] 필터, 인터셉터, AOP 정리 ] 입니다. : ) 공통 프로세스에 대한 고민 자바 웹 개발을 하다보면, 공통..
goddaehee.tistory.com
Controller로 가기 전 처리해야 될 내용을 Interceptor에서 처리
-> 스프링의 모든 Bean 접근 가능
-> Dispatcher Servlet과 Controller사이의 요청을 가로채서 필요한 작업을 처리한다고 보면 된다.
클래스 생성 후 특정 클래스 상속할 수 있도록 하기
> LoginCheckInterceptor.java
package com.kh.mvc.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class LoginCheckInterceptor extends HandlerInterceptorAdapter{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 컨트롤러가 실행되기 전에 필요한 작업을 할 수 있는 메소드이다.
// 반환값이 false일 경우 컨트롤러를 실행하지 않는다.
log.info("preHandle() call..");
return super.preHandle(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// 컨트롤러가 실행된 후에 필요한 작업을 할 수 있는 메소드이다.
log.info("postHandle() call..");
super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// 컨트롤러의 처리가 끝나고 화면(View) 처리까지 모두 완료되면 실행되는 메소드이다.
log.info("afterCompletion() call..");
super.afterCompletion(request, response, handler, ex);
}
@Override
public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 비동기 요청 시 postHandle, afterCompletion이 수행되지 않고 afterConcurrentHandlingStarted 메소드가 실행된다.
log.info("afterConcurrentHandlingStarted() call..");
super.afterConcurrentHandlingStarted(request, response, handler);
}
}
servlet-context에서 interceptor 관리를 한다. -> 웹관련 설정이기 때문
> servlet-context.xml
<!--
인터셉터 설정
- 인터셉터가 웹 관련 설정이기 때문에 root-context.xml이 아닌 servlet-context.xml에 작성한다.
-->
<interceptors>
<interceptor>
<!-- 인터셉터를 적용시킬 요청(컨트롤러) 선택
<mapping path="/member/myPage"/>
<mapping path="/member/update"/>
와일드카드 /*, /**의 차이점
/member/*
- /member/insert (O)
- /member/update (O)
- /member/insert/10 (X)
- /member/update/user (X)
/member/**
- /member/insert (O)
- /member/update (O)
- /member/insert/10 (O)
- /member/update/user (O)
-->
<mapping path="/member/**"/>
<!-- 인터셉터를 제외시킬 요청(컨트롤러) 선택 -->
<exclude-mapping path="/member/enroll"/>
<exclude-mapping path="/member/idCheck"/>
<!-- 인터셉터 등록 -->
<beans:bean id="loginCheckInterceptor" class="com.kh.mvc.common.interceptor.LoginCheckInterceptor"/>
</interceptor>
</interceptors>
LoginCheckInterceptor 패키지명 변경 후 남아있는 빈 폴더 삭제
- preHandle에 로직 작성
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 컨트롤러가 실행되기 전에 필요한 작업을 할 수 있는 메소드이다.
// 반환값이 false일 경우 컨트롤러를 실행하지 않는다.
log.info("preHandle() call..");
Member loginMember = (Member) request.getSession().getAttribute("loginMember");
if(loginMember == null) {
request.setAttribute("msg", "로그인 후 이용이 가능합니다.");
request.setAttribute("location", "/");
request.getRequestDispatcher("/WEB-INF/views/common/msg.jsp").forward(request, response);
return false;
}
return super.preHandle(request, response, handler);
}
interceptor
/*
* 인터셉터
* - 컨트롤러에 들어오는 요청(HttpRequest)과 응답(HttpResponse)을 가로채는 역할을 한다.
* - 인터셉터를 구현하기 위해서는 HandlerInterceptorAdapter 클래스를 상속하는 방법으로 구현해야 한다.
*
* 필터와의 차이점
* - 필터는 Servlet 수행 전에 실행된다. Spring 자원을 이용할 수 없다. (web.xml에 설정)
* - 인터셉터는 DispatcherServlet 수행 후 컨트롤러에 요청을 넘기기 전에 실행된다. Spring 자원을 이용할 수 있다. (Servlet-context.xml에 설정)
*
*/
요청 처리 - 필터, 인터셉터
비즈니스 로직 적용 - AOP -> 서비스 앞뒤로 감싸는 역할
- 회원정보 수정 로직 작성
- 요청을 받아서 처리할 메소드가 없기 때문에 404에러 발생
- post 요청 (@PostMapping)
@PostMapping("/member/update")
public String update() {
return "member/myPage";
}
로그인이 되어 있어야 update가 가능하기 때문에 interceptor를 탈 수 있게 아래 코드를 작성해준다.
<mapping path="/member/update"/>
Controller에서 수정하기 눌렀을 때 수정한 데이터가 잘 넘어올 수 있게 Model 객체로 받아와야 한다.
이 과정에서 Set을 해줄 때 name속성과 필드명이 동일해야 적용이 가능하다.
그리고 save에서 update 로직을 수행할 시 member객체의 no값이 0이 아니어야 한다. -> 따로 안받아왔기 때문
처리 방법 : 1. no값을 hidden으로 숨겨서 같이 보내기
2. SessionAttribute 활용
@PostMapping("/member/update")
public ModelAndView update(
ModelAndView model,
@SessionAttribute(name="loginMember") Member loginMember,
@ModelAttribute Member member) {
int result = 0;
member.setNo(loginMember.getNo());
result = service.save(member);
if(result > 0) {
model.addObject("loginMember", member);
model.addObject("msg", "회원정보 수정을 완료했습니다.");
model.addObject("location", "/member/myPage");
} else {
model.addObject("msg", "회원정보 수정에 실패했습니다.");
model.addObject("location", "/member/myPage");
}
model.setViewName("common/msg");
return model;
}
> MemberServiceImpl.java
@Override
@Transactional
public int save(Member member) {
int result = 0;
if(member.getNo() != 0) {
// update
result = mapper.updateMember(member);
} else {
// 패스워드 암호화
member.setPassword(passwordEncoder.encode(member.getPassword()));
// insert
result = mapper.insertMember(member);
}
// if(true) {
// throw new RuntimeException();
// }
return result;
}
> MemberMapper.java
@Mapper
public interface MemberMapper {
// @Select("select * from member")
// List<Member> findAll();
// 아래 메소드를 호출 시 실제 mapper.xml에 있는 쿼리문을 수행한 다음 결과를 리턴해주는 인터페이스의 구현체가 만들어진다.
Member findMemberById(@Param("id") String id);
int insertMember(Member member);
int updateMember(Member member);
}
메소드도 추가 시켜줌
- session 갱신
-> service에서 찾아서 넣어주기 (MemberController.java)
model.addObject("loginMember", service.findMemberById(loginMember.getId()));
> MemberService.java
package com.kh.mvc.member.model.service;
import org.springframework.transaction.annotation.Transactional;
import com.kh.mvc.member.model.vo.Member;
//@Transactional
public interface MemberService {
Member findMemberById(String id);
Member login(String id, String password);
int save(Member member);
Boolean isDuplicateID(String userId);
}
> MemberServiceImpl.java
package com.kh.mvc.member.model.service;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.kh.mvc.member.model.dao.MemberMapper;
import com.kh.mvc.member.model.vo.Member;
//@Service("빈 ID")
@Service
//@Transactional
public class MemberServiceImpl implements MemberService {
@Autowired
private MemberMapper mapper;
@Autowired
private BCryptPasswordEncoder passwordEncoder;
// @Autowired
// private SqlSession session;
@Override
public Member findMemberById(String id) {
return mapper.findMemberById(id);
}
@Override
public Member login(String id, String password) {
Member member = null;
// member = dao.findMemberById(session, id);
member = this.findMemberById(id);
// System.out.println(mapper.findAll());
// System.out.println(passwordEncoder.encode(password));
// System.out.println(member.getPassword());
// System.out.println(passwordEncoder.matches(password, member.getPassword()));
// if (member != null && member.getPassword().equals(passwordEncoder.encode(password))) {
// return member;
// } else {
// return null;
// }
return member != null &&
passwordEncoder.matches(password, member.getPassword()) ? member : null;
}
@Override
@Transactional
public int save(Member member) {
int result = 0;
if(member.getNo() != 0) {
// update
result = mapper.updateMember(member);
} else {
// 패스워드 암호화
member.setPassword(passwordEncoder.encode(member.getPassword()));
// insert
result = mapper.insertMember(member);
}
// if(true) {
// throw new RuntimeException();
// }
return result;
}
@Override
public Boolean isDuplicateID(String id) {
return this.findMemberById(id) != null;
}
}
-> findMemberById 수정
<!--
인터셉터 설정
- 인터셉터가 웹 관련 설정이기 때문에 root-context.xml이 아닌 servlet-context.xml에 작성한다.
-->
<interceptors>
<interceptor>
<!-- 인터셉터를 적용시킬 요청(컨트롤러) 선택
<mapping path="/member/myPage"/>
<mapping path="/member/update"/>
와일드카드 /*, /**의 차이점
* : 한 스텝에 대해서만 어떤 값이 와도 성공, 그 다음 스텝이 추가되면 실패함
/member/*
- /member/insert (O)
- /member/update (O)
- /member/insert/10 (X)
- /member/update/user (X)
** : 현재 스텝 뿐만 아니라 그 하위 스텝까지도 허용
/member/**
- /member/insert (O)
- /member/update (O)
- /member/insert/10 (O)
- /member/update/user (O)
아래는 전체 적용
-->
<mapping path="/member/**"/>
<!--
인터셉터를 제외시킬 요청(컨트롤러) 선택
: ex. member로 시작하는 요청들 중 제외하고 싶은 요청만 뺄 수 있다.
-->
<exclude-mapping path="/member/enroll"/>
<exclude-mapping path="/member/idCheck"/>
<!-- 인터셉터 등록 -->
<beans:bean id="loginCheckInterceptor" class="com.kh.mvc.common.interceptor.LoginCheckInterceptor"/>
</interceptor>
</interceptors>
* 인터셉터를 통한 로그인체크
- 회원 탈퇴
@GetMapping("/member/delete")
public String delete() {
return "member/myPage";
}
interceptor에 작업을 해놨기 때문에
<mapping path="/member/**"/>
로그인체크가 적용이 된다.
- 비즈니스 로직 작성
> MemberController.java
@GetMapping("/member/delete")
public ModelAndView delete(ModelAndView model,
@SessionAttribute(name="loginMember") Member loginMember) {
int result = 0;
result = service.delete(loginMember.getNo());
if(result > 0) {
model.addObject("msg", "정상적으로 탈퇴되었습니다.");
model.addObject("location", "/logout");
} else {
model.addObject("msg", "회원 탈퇴에 실패하였습니다.");
model.addObject("location", "/member/myPage");
}
model.setViewName("common/msg");
return model;
}
-> 탈퇴 후 logout, 실패 시 myPage로 넘겨준다.
> MemberService.java
package com.kh.mvc.member.model.service;
import org.springframework.transaction.annotation.Transactional;
import com.kh.mvc.member.model.vo.Member;
//@Transactional
public interface MemberService {
Member findMemberById(String id);
Member login(String id, String password);
int save(Member member);
Boolean isDuplicateID(String userId);
int delete(int no);
}
-> delete추가
> MemberServiceImpl.java 에서 delete 정의된 메소드 추가
@Override
public int delete(int no) {
return 0;
}
mapper를 통해서 쿼리문을 실행시켜줄 것이기 때문에 return값 수정
@Override
public int delete(int no) {
return mapper.deleteMember(no);
}
> member-mapper.xml
<delete id="deleteMember" parameterType="_int">
UPDATE MEMBER
SET
STATUS = 'N'
WHERE
NO = #{no}
</delete>
> MemberMapper.java 에 deleteMember 추가
package com.kh.mvc.member.model.dao;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import com.kh.mvc.member.model.vo.Member;
@Mapper
public interface MemberMapper {
// @Select("select * from member")
// List<Member> findAll();
// 아래 메소드를 호출 시 실제 mapper.xml에 있는 쿼리문을 수행한 다음 결과를 리턴해주는 인터페이스의 구현체가 만들어진다.
Member findMemberById(@Param("id") String id);
int insertMember(Member member);
int updateMember(Member member);
int deleteMember(int no);
}
logout을 GetMapping으로 수정
> home.jsp
<form action="${ path }/logout" method="get">
<button type="submit">로그아웃</button>
</form>
> MemberController.java
// 로그아웃 처리 (SessionStatus 객체 사용)
@GetMapping("/logout")
public String logout(SessionStatus status) {
log.info("status.isComplete() : {}", status.isComplete());
// SessionStatus 객체의 setComplete() 메소드로 세션 스코프로 확장된 객체들을 지워준다.
status.setComplete();
log.info("status.isComplete() : {}", status.isComplete());
return "redirect:/";
}
'국비지원_Java > Java Programming_2' 카테고리의 다른 글
자바 프로그래밍_Day_112_게시글 작성 (0) | 2022.03.02 |
---|---|
자바 프로그래밍_Day_111_게시글 목록 조회 (0) | 2022.02.22 |
자바 프로그래밍_Day_109_회원정보 관련 (0) | 2022.02.18 |
자바 프로그래밍_Day_108_로그인, 로그아웃, 회원가입 구현 (0) | 2022.02.18 |
자바 프로그래밍_Day_107_Spring MVC, mybatis 연동 (0) | 2022.02.15 |