본문 바로가기
study/Spring

[Spring] 24. Spring (사용자등록[user.sql, User.java, userEntry.jsp, UserController.java, UserDao.java])

by 금이패런츠 2022. 5. 6.
728x90
반응형

user.sql

create table useraccount (
   userid varchar2(10) primary key,
   password varchar2(15),
   username varchar2(20),
   phoneno varchar2(20),
   postcode varchar2(7),
   address varchar2(30),
   email varchar2(50),
   birthday date
);

select * from USERACCOUNT;

User.java

package logic;

import java.util.Date;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Past;
import javax.validation.constraints.Size;

import org.springframework.format.annotation.DateTimeFormat;

public class User {
	@Size(min=3, max=10, message="아이디는 3자 이상 10자 이하로 입력하세요.")
	private String userid;
	@Size(min=3, max=10, message="비밀번호는 3자 이상 10자 이하로 입력하세요.")
	private String password;
	@NotEmpty(message="사용자 이름은 필수입니다.")
	private String username;
	private String phoneno;
	private String postcode;
	private String address;
	@NotEmpty(message="email은 필수입니다.")
	@Email(message="email 형식으로 입력하세요.")
	private String email;
	@Past(message="생일은 과거 날짜만 가능합니다.")
	@DateTimeFormat(pattern="yyyy-MM-dd") // 형식 오류 시 typeMismatch.birthday 코드값 저장
	private Date birthday;
	//getter, setter, toString
	public String getUserid() {
		return userid;
	}
	public void setUserid(String userid) {
		this.userid = userid;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPhoneno() {
		return phoneno;
	}
	public void setPhoneno(String phoneno) {
		this.phoneno = phoneno;
	}
	public String getPostcode() {
		return postcode;
	}
	public void setPostcode(String postcode) {
		this.postcode = postcode;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public Date getBirthday() {
		return birthday;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	@Override
	public String toString() {
		return "User [userid=" + userid + ", password=" + password + ", username=" + username + ", phoneno=" + phoneno
				+ ", postcode=" + postcode + ", address=" + address + ", email=" + email + ", birthday=" + birthday
				+ "]";
	}
}

userEntry.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%-- /springmvc1/src/main/webapp/WEB-INF/view/user/userEntry.jsp --%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>사용자 등록</title>
</head>
<body>
	<h2>사용자 등록</h2>
	<form:form modelAttribute="user" method="post" action="userEntry">
	<%-- global 오류 화면 출력 부분 --%>
		<spring:hasBindErrors name="user">
			<font color="red">
			<%--${errors.globalErrors } : Controller 에서 BindingResult.reject() 함수로 설정한 오류 --%>
			 <c:forEach items="${errors.globalErrors }"	var="error">
					<spring:message code="${error.code }" />
			 </c:forEach></font>
		</spring:hasBindErrors>
		
		<table border="1" style="border-collapse: collapse;">
			<tr>
				<td>아이디</td>
				<td><form:input path="userid" />
				   <font color="red"><form:errors path="userid" /></font></td>
			</tr>
			<tr>
				<td>비밀번호</td>
				<td><form:password path="password" />
				 <font color="red"><form:errors	path="password" /></font></td>
			</tr>
			<tr>
				<td>이름</td>
				<td><form:input path="username" />
				 <font color="red"><form:errors	path="username" /></font></td>
			</tr>
			<tr>
				<td>전화번호</td>
				<td><form:input path="phoneno" />
				 <font color="red"><form:errors	path="phoneno" /></font></td>
			</tr>
			<tr>
				<td>우편번호</td>
				<td><form:input path="postcode" />
				 <font color="red"><form:errors	path="postcode" /></font></td>
			</tr>
			<tr>
				<td>주소</td>
				<td><form:input path="address" />
				 <font color="red"><form:errors	path="address" /></font></td>
			</tr>
			<tr>
				<td>이메일</td>
				<td><form:input path="email" />
				 <font color="red"><form:errors	path="email" /></font></td>
			</tr>
			<tr>
				<td>생년월일</td>
				<td><form:input path="birthday" />
				 <font color="red"><form:errors	path="birthday" /></font></td>
			</tr>
			<tr>
				<td colspan="2" align="center">
				  <input type="submit" value="등록">
				  <input type="reset" value="초기화"></td>
			</tr>
		</table>
	</form:form>
</body>
</html>

UserController.java

package controller;

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

import javax.servlet.http.HttpSession;
import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import exception.LoginException;
import logic.Sale;
import logic.ShopService;
import logic.User;

@Controller
@RequestMapping("user")
public class UserController {
	@Autowired
	private ShopService service;
	
	//@GetMapping : Get 방식 요청인 경우
	//@PostMapping : Post 방식 요청인 경우
	//@RequestMapping : Get/Post 방식 상관없이 모든 요청
	
	//http://localhost:8088/springmvc1/user/userEntry
	@GetMapping("*") //그 외 모든 Get 방식요청
	public ModelAndView getUser() {
		ModelAndView mav = new ModelAndView();
		mav.addObject(new User());
		return mav; // /WEB-INF/view/user/userEntry.jsp 뷰로 설정
	}
	@PostMapping("userEntry") // POST 방식으로 user/userEntry url 요청시 
	public ModelAndView userEntry(@Valid User user, BindingResult bresult) {
		ModelAndView mav = new ModelAndView();
		if(bresult.hasErrors()) {
			mav.getModel().putAll(bresult.getModel());
			//reject : 뷰의 globalErrors의 내용으로 저장
			bresult.reject("error.input.user");
			return mav; // /WEB-INF/view/user/userEntry.jsp
		}
		try {
			service.userInsert(user);
			mav.addObject("user", user);
			//userid가 기본키 설정됨. userid 중복된 경우 예외 발생
		} catch(DataIntegrityViolationException e) {
			e.printStackTrace();
			bresult.reject("error.duplicate.user");
			mav.getModel().putAll(bresult.getModel());
			return mav;
		}
		mav.setViewName("redirect:login");
		return mav;
	}
	/* 로그인 - POST 방식 요청
	 * 1. 유효성검증
	 *    User객체에 저장된 파라미터값을 이용하여 유효성검증.
	 * 2. 입력받은 userid,password 로 db에서 해당 정보를 읽기.
	 *     - userid가 없는 경우 
	 *     - password가 틀린 경우
	 *     - 정상적인 사용자인경우 : session에 로그인 정보 등록하기         
	 */
	@PostMapping("login") // POST 방식으로 user/userEntry url 요청시 
	public ModelAndView login(@Valid User user, BindingResult bresult, HttpSession session) {
		ModelAndView mav = new ModelAndView();
		if(bresult.hasErrors()) {
			mav.getModel().putAll(bresult.getModel());
			bresult.reject("error.input.login");
			return mav;
		}
		try {
			//dbuser : userid에 해당하는 db의 레코드 값 저장
			User dbUser = service.userSelectOne(user.getUserid());
			if(user.getPassword().equals(dbUser.getPassword())) { //비밀번호 검증. 일치
				session.setAttribute("loginUser", dbUser);
			} else { //비밀번호 검증. 불일치
				bresult.reject("error.login.password");
				mav.getModel().putAll(bresult.getModel());
				return mav;
			}
			//EmptyResultDataAccessException : 해당 레코드 없음
		} catch(EmptyResultDataAccessException e) {
			bresult.reject("error.login.id");
			mav.getModel().putAll(bresult.getModel());
			return mav;
		}
		mav.setViewName("redirect:mypage?id=" + user.getUserid());
		return mav;
	}
	//loginCheck * 로 시작하는 메서드명이 실행시 로그인 여부 검증하기 => AOP사용
	@RequestMapping("logout")
	public String loginChecklogout(HttpSession session) {
		session.invalidate();
		return "redirect:login"; //view 리턴
	}
	// http://localhost:8088/springmvc1/user/main
	// http://localhost:8088/springmvc1/user/password
	/*
	 * 1. 로그인필요
	 * 2.password.jsp 페이지 출력
	 */
	@GetMapping({"main","password"})
	public String loginCheckmain(HttpSession session) {
		return null; //url과 같은 이름의 view 리턴 : user/main.jsp or user/password.jsp
	}
//	@GetMapping("password")
//	public String loginCheckpassword(HttpSession session) {
//		return null; //url과 같은 이름의 view 리턴 : user/main.jsp
//	}
	
	
	/*
	 * AOP 설정하기 : UserLoginAspect 클래스의 userIdCheck 메서드로 구현하기.
	 * 1. pointcut : UserController 클래스의 idCheck로 시작하는 메서드이면서 마지막 매개변수가 id, session인 경우
	 * 2. 로그인 여부 검증. 로그인이 안된 경우 "로그인 후 거래하세요." 메세지 출력하고 login페이지 호출.
	 * 3. admin이 아니면서, 로그인 아이디와 id값이 다른 경우 "본인 정보만 거래 가능합니다." 메세지 출력하고 main페이지 호출.					
	 */
	@RequestMapping("mypage")
	public ModelAndView idCheckmypage(String id, HttpSession session) {
		ModelAndView mav = new ModelAndView();
		//1. db에서 id 해당하는 User 객체조회
		User user = service.userSelectOne(id);
		//2. 주문목록 조회
		//salelist : 주문목록, 주문번호별 주문상품목록, 주문상품별 상품정보 저장
		List<Sale> salelist = service.salelist(id);
		mav.addObject("user", user);
		mav.addObject("salelist", salelist);
		return mav;
	}
	@GetMapping({"update","delete"})
	public ModelAndView idCheckupdate(String id, HttpSession session) {
		ModelAndView mav = new ModelAndView();
		User user = service.userSelectOne(id);
		mav.addObject("user", user);
		return mav;
	}
	/*
	 * 1. 유효성 검증하기.
	 * 2. 비밀번호 검증  
	 *     - 비밀번호 오류 : error.login.password 코드를 입력하여, update.jsp 페이지로 이동.
	 * 3. userid에 해당하는 고객 정보를 수정하기 : ShopService.userUpdate 함수
	 * 4. 수정 성공 : session의 로그인 정보 수정
	 *              main 페이지 이동
	 *    수정 실패 : 수정실패 메세지 출력. update 페이지 이동하기       
	 */
	@PostMapping("update") // POST 방식으로 user/userEntry url 요청시 
	public ModelAndView update(@Valid User user, BindingResult bresult, HttpSession session) {
		ModelAndView mav = new ModelAndView();
		//1. 유효성 검증하기
		if(bresult.hasErrors()) {
			mav.getModel().putAll(bresult.getModel());
			return mav;
		}
		//2. 비밀번호 검증 
		//admin 로그인시 비밀번호는 admin 비밀번호로 검증
		//본인 로그인시 비밀번호는 본인 비밀번호로 검증
		User loginUser = (User)session.getAttribute("loginUser");
		if(!loginUser.getPassword().equals(user.getPassword())) {
			bresult.reject("error.login.password");
			mav.getModel().putAll(bresult.getModel());
		}
		//3. userid에 해당하는 고객 정보를 수정하기
		try {
			service.userUpdate(user);
			if(user.getUserid().equals(loginUser.getUserid())) //본인정보 수정시에만 로그인정보 수정
				session.setAttribute("loginUser", user);
			// 4. 수정 성공, 수정 실패
			mav.setViewName("redirect:main");
		} catch (Exception e) {
			e.printStackTrace(); //수정 실패
			throw new LoginException("고객 정보 수정 실패", "update?id="+user.getUserid());
		}
		return mav;
	}
	/*
	 * 1. loginCheckPassword : 로그인 여부 검증
	 * 2. @RequestParam : 요청파라미터를 Map객체로 저장
	 * 		req.put("password",password 파라미터값)
	 * 		req.put("chgpass",chgpass 파라미터값)
	 * 		req.put("chgpass2",chgpass2 파라미터값)
	 * 3. 입력된 현재 비밀번호와 로그인 된 정보의 비밀번호 일치 검증
	 * 4. db 변경하기
	 * 5. 성공시 : 로그인 정보 변경. main 페이지 이동
	 * 	  실패시 : 오류 메세지 출력. password 페이지 이동
	 */
	@PostMapping("password")
	public ModelAndView loginCheckPassword(@RequestParam Map<String,String> req, HttpSession session) {
		User loginUser = (User)session.getAttribute("loginUser");
		//3. 입력된 현재 비밀번호와 로그인 된 정보의 비밀번호 일치 검증
		//req.get("password") : 현재 비밀번호
		//loginUser.getPassword() : 등록된 비밀번호
		if(!req.get("password").equals(loginUser.getPassword())) {
			throw new LoginException("비밀번호 오류 입니다.","password");
		}
		//비밀번호가 일치하는 경우 실행
		ModelAndView mav = new ModelAndView();
		try {
			//req.get("chgpass") : 변경할 비밀번호
			service.userChgPassword(loginUser.getUserid(),req.get("chgpass")); //db변경
			loginUser.setPassword(req.get("chgpass")); //session의 loginUser 객체의 비밀번호 수정
			mav.addObject("message", "비밀번호가 변경되었습니다.");
			mav.setViewName("redirect:main");
		} catch (Exception e) {
			throw new LoginException("비밀번호 수정시 오류가 있습니다.", "password");
		}
		return mav;
	}
	/*
	 * 회원탈퇴
	 * 1.파라미터 정보 저장.
	 *   - 관리자인 경우 탈퇴 불가
	 * 2.비밀번호 검증 
	 *   본인탈퇴 : 본인 비밀번호 
	 *   관리자가 타인 탈퇴 : 관리자 비밀번호
	 * 3.비밀번호 불일치 
	 *   메세지 출력 후 delete 페이지 이동  
	 * 4.비밀번호 일치
	 *   db에서 해당 사용자정보 삭제하기
	 *   본인탈퇴 : 로그아웃, login 페이지 이동
	 *   관리자탈퇴 : admin/list 페이지 이동 => 404 오류 발생
	 */
	@PostMapping("delete")
	public ModelAndView idCheckdelete(String password, String userid, HttpSession session) {
		//password 매개변수 : password 이름의 파라미터 값 저장
		//userid 매개변수 : userid 이름의 파라미터 값 저장
		ModelAndView mav = new ModelAndView();
		if(userid.equals("admin")) throw new LoginException("관리자 탈퇴는 불가능합니다.", "main");
		User loginUser = (User)session.getAttribute("loginUser"); //로그인 정보
		if(!password.equals(loginUser.getPassword())) {
			throw new LoginException("비밀번호를 확인하세요.", "delete?id=" + userid);
		}
		try {
			service.userDelete(userid);
		} catch (Exception e) {
			e.printStackTrace();
			throw new LoginException("탈퇴시 오류발생.", "delete?id=" + userid);
		}
		if(loginUser.getUserid().equals("admin")) { //관리자가 사용자 강제탈퇴
			mav.setViewName("redirect:../admin/list");
		} else { //일반사용자 본인이 탈퇴
			mav.setViewName("redirect:login");
			session.invalidate(); //session 무효화
			return mav;
		}
		return mav;
	}
	/*
	 * {url}search : {url} 지정하지 않음. *search인 요청인 경우 호출되는 메서드 지정
	 * @PathVariable String url : {url}값을 매개변수 전달.
	 * 		http://localhost:8088/springmvc1/user/idsearch 요청
	 * 		url : id 값 저장
	 * 		http://localhost:8088/springmvc1/user/pwsearch 요청
	 * 		url : pw 값 저장
	 */
	@PostMapping("{url}search")
	public ModelAndView search(User user, BindingResult bresult, @PathVariable String url) {
		ModelAndView mav = new ModelAndView();
		String code = "error.userid.search"; //아이디를 찾을 수 없습니다. 메세지의 코드값
		String title = "아이디";
		if(user.getEmail() == null || user.getEmail().equals("")) { //email 값이 없을 때.
			//rejectValue : 컬럼별로 오류 메세지 저장
			// <form:errors path="email" /> 영역에 오류 메세지 출력
			bresult.rejectValue("email", "error.required"); //@Valid에서 처리해주는 방식.
		}
		if(user.getPhoneno() == null || user.getPhoneno().equals("")) {
			// <form:errors path="phoneno" /> 영역에 오류 메세지 출력
			bresult.rejectValue("phoneno", "error.required"); //message.properties에서 처리.
		}
		if(url.equals("pw")) {
			title = "비밀번호";
			code = "error.password.search"; //비밀번호를 찾을 수 없습니다. 메세지의 코드값
			if(user.getUserid() == null || user.getUserid().equals("")) {
				bresult.rejectValue("userid", "error.required");
			}
		}
		if(bresult.hasErrors()) { //rejectValue 함수로 오류가 존재
			mav.getModel().putAll(bresult.getModel());
			return mav;
		}
		String result = null;
		try {
			//아이디 검색 : 아이디 값
			//비밀번호 검색 : 비밀번호 값
			//user : 화면에서 입력된 파라미터 값 저장 (email. phoneno, userid)
			result = service.getSearch(user,url);
		} catch (EmptyResultDataAccessException e) {
			//EmptyResultDataAccessException : 조회결과가 없는 경우 발생되는 예외
			//<spring:message code="${error.code}" /> 영역에 표시됨
			bresult.reject(code);
			mav.getModel().putAll(bresult.getModel());
			return mav;
		}
		mav.addObject("result",result);
		mav.addObject("title",title);
		mav.setViewName("search"); //  /WEB-INF/view/search.jsp
		return mav;
	}
}

UserDao.java

package dao;

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

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.stereotype.Repository;

import logic.User;

@Repository
public class UserDao {
	private NamedParameterJdbcTemplate template;
	private Map<String,Object> param = new HashMap<String,Object>();
	private RowMapper<User> mapper = new BeanPropertyRowMapper<>(User.class);
	@Autowired
	public void setDateSource(DataSource dataSource) { 
		template = new NamedParameterJdbcTemplate(dataSource);
	}
	public void insert(User user) {
		SqlParameterSource param = new BeanPropertySqlParameterSource(user);
		String sql = "insert into useraccount "
				+ " (userid, password, username, phoneno, postcode, address, email, birthday)"
				+ " values (:userid, :password, :username, :phoneno, :postcode, :address, :email, :birthday)";
				template.update(sql, param);
	}
	public User selectOne(String userid) {
		param.clear();
		param.put("userid", userid);
		return template.queryForObject("select * from useraccount where userid=:userid", param, mapper);
	}
	public void update(User user) {
		SqlParameterSource param = new BeanPropertySqlParameterSource(user);
		String sql = "update useraccount set username=:username,  birthday=:birthday, "
				+ " phoneno=:phoneno, postcode=:postcode, address=:address, email=:email "
				+ " where userid=:userid";
				template.update(sql, param);
	}
	public void passwordupdate(String userid, String chgpass) {
		String sql = "update useraccount set password= :password where userid=:userid";
		param.clear();
		param.put("userid", userid);
		param.put("password", chgpass);
		template.update(sql, param);
	}
	public void delete(String userid) {
		param.clear();
		param.put("userid", userid);
		template.update("delete from useraccount where userid=:userid", param);
	}
	public List<User> list() {
		return template.query("select * from useraccount", param, mapper);
	}
	public String search(User user, String url) {
		String sql = null;
		if(url.equals("id")) { //idsearch인 경우
			// || : concat기능. (userid-2) + "**"
			//		오라클에서 두개의 문자열을 연결해주는 연산자
			sql = "select substr(userid, 1, length(userid) -2) || '**' from useraccount "
					+ " where email=:email and phoneno=:phoneno";
		}
		else if(url.equals("pw")) {  //pwsearch인 경우
			sql = "select '**' || substr(password, 3, length(password) -2) from useraccount "
					+ " where userid=:userid and email=:email and phoneno=:phoneno";
		}
		SqlParameterSource param = new BeanPropertySqlParameterSource(user);
		return template.queryForObject(sql, param, String.class);
	}
}
728x90
반응형