회원 가입 데이터 베이스 설계는 다음과 같이 하였다.
-- 데이터베이스 생성 CREATE DATABASE SIMPLEBLOG2 CHARACTER SET=UTF8; -- 유저 생성 CREATE USER `SIMPLEBLOG2`@`LOCALHOST` IDENTIFIED BY '1111'; -- 권한 부여 GRANT ALL PRIVILEGES ON SIMPLEBLOG2.* TO `SIMPLEBLOG2`@`LOCALHOST`; /**********************************/ /* Table Name: 회원 */ /**********************************/ CREATE TABLE users( idx INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(45) UNIQUE NOT NULL COMMENT '아이디' , nickname VARCHAR(30) NULL COMMENT ' 닉네임', password VARCHAR(100) NULL COMMENT '비밀번호', email VARCHAR(50) NULL comment '이메일', enabled INTEGER NOT NULL DEFAULT 1 COMMENT '계정사용여부', upoint INT COMMENT '포인트', regdate TIMESTAMP DEFAULT now() ); CREATE TABLE user_roles ( user_role_id int(11) NOT NULL AUTO_INCREMENT, username VARCHAR(45) UNIQUE NOT NULL COMMENT '아이디', nickname VARCHAR(30) NULL COMMENT ' 닉네임', role varchar(45) NOT NULL, PRIMARY KEY (user_role_id), UNIQUE KEY uni_username_role (role,username) ); ALTER TABLE user_roles ADD FOREIGN KEY (username) REFERENCES users(username); /**********************************/ /* Table Name: 권한 */ /**********************************/ CREATE TABLE authorities( username VARCHAR(45) NOT NULL COMMENT '회원아이디', authority VARCHAR(20) NOT NULL COMMENT '권한' ); ALTER TABLE authorities ADD CONSTRAINT IDX_authorities_FK0 FOREIGN KEY (username) REFERENCES users (username); /**********************************/ /* Table Name: 그룹 */ /**********************************/ CREATE TABLE groups( id VARCHAR(20) PRIMARY KEY NOT NULL COMMENT '그룹 아이디', group_name VARCHAR(20) NULL COMMENT '그룹 명' ); /**********************************/ /* Table Name: 그룹 권한 관계 */ /**********************************/ CREATE TABLE group_authorities( group_id VARCHAR(20) NOT NULL COMMENT '그룹 아이디', authority VARCHAR(20) NOT NULL COMMENT '권한' ); ALTER TABLE group_authorities ADD CONSTRAINT IDX_group_authorities_FK0 FOREIGN KEY (group_id) REFERENCES groups (id); /**********************************/ /* Table Name: 그룹 회원 관계 */ /**********************************/ CREATE TABLE group_members( group_id VARCHAR(20) NOT NULL COMMENT '그룹 아이디', username VARCHAR(45) NOT NULL COMMENT '회원 아이디' ); ALTER TABLE group_members ADD CONSTRAINT IDX_group_members_FK0 FOREIGN KEY (username) REFERENCES users (username); ALTER TABLE group_members ADD CONSTRAINT IDX_group_members_FK1 FOREIGN KEY (group_id) REFERENCES groups (id); -- 회원 데이터 입력 INSERT INTO users (username, password, enabled) VALUES ('user', '1', 1); INSERT INTO users (username, password, enabled) VALUES ('admin', '1', 1); -- 회원 권한 입력 INSERT INTO authorities (username, authority) VALUES ('user', 'ROLE_USER'); INSERT INTO authorities (username, authority) VALUES ('admin', 'ROLE_ADMIN'); INSERT INTO authorities (username, authority) VALUES ('admin', 'ROLE_USER'); -- 그룹 INSERT INTO groups (id, group_name) VALUES ('G01', '관리자 그룹'); INSERT INTO groups (id, group_name) VALUES ('G02', '사용자 그룹'); -- 그룹 권한 INSERT INTO group_authorities (group_id, authority) VALUES ('G01', 'ROLE_ADMIN'); INSERT INTO group_authorities (group_id, authority) VALUES ('G01', 'ROLE_USER'); INSERT INTO group_authorities (group_id, authority) VALUES ('G02', 'ROLE_USER'); -- 그룹 회원 INSERT INTO group_members (group_id, username) VALUES ('G01', 'admin'); INSERT INTO group_members (group_id, username) VALUES ('G02', 'user');
ER 다이어 그램
이클립스 에서 ERMaster 를 설치하면 된다.
설치 방법 : [ERD TOOL] ECLIPSE ERMASTER PLUG-IN 설치
나비켓 프리미엄 모델링 이다.
만약 현재 블로그 포스팅이 이해가 안되면 이전에 포스팅한 주소를 참조 하기를 바란다.
1. 스프링 시큐리티 유효성 JSR-303 설정 방법 - 각종 @Pattern 정규식 유효성 체크 모음 스프링 설정 12 - CJH - 12 ★
2. 스프링 시큐리티 로그인 설정 13 - CJH - 13 ★
3. 스프링 시큐리티(Spring Security) 이용한 비밀번호 암호화 로그인 및 테스트 방법Bcrypt, Sha-256 등의 설정 15 - CJH - 15
pom.xml
시큐리티 의존성 라이브러리 설정
<!-- 시큐리티 최소 의존성 --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>4.2.1.RELEASE</version> </dependency>
security-context.xml
<intercept-url pattern="/member/**" access="permitAll" />
회원 가입 페이지 권한 설정이다.
<beans:bean id="bcryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
비밀번호 암호를 의존성 주입 한다.
<!-- 검사 URL --> <http use-expressions="true"> <intercept-url pattern="/sample/**" access="permitAll"/> <intercept-url pattern="/ajaxTest/**" access="permitAll"/> <intercept-url pattern="/login/loginForm.do" access="permitAll"/> <intercept-url pattern="/admin/**" access="hasRole('ADMIN')"/> <intercept-url pattern="/login" access="hasRole('USER')" /> <intercept-url pattern="/" access="permitAll"/> <intercept-url pattern="/user/**" access="hasAnyRole('USER, ADMIN')" /> <intercept-url pattern="/member/**" access="permitAll" /> <intercept-url pattern="/passwordEncoderTest" access="permitAll"/> <form-login login-page="/login/loginForm.do" default-target-url="/" authentication-failure-url="/login/loginForm.do?error" username-parameter="id" password-parameter="password" /> <logout logout-url="/logout" logout-success-url="/" /> <access-denied-handler error-page="/login/accessDenied.do"/> <remember-me key="REMEMBER_ME_KEY"/> </http> <beans:bean id="bcryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
UsersVO
/** * <pre> * 1. 패키지명 : net.macaronics.web.domain * 2. 타입명 : UsersVO.java * 3. 작성일 : 2017. 12. 26. 오후 7:48:05 * 4. 저자 : 최준호 * * </pre> * */ package net.macaronics.join.domain; import java.sql.Timestamp; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; import org.hibernate.validator.constraints.NotBlank; public class UsersVO { private int idx; // 자동 증가 @NotBlank @Size(min=4, max=30, message="아이디의 크기는 4에서 20 사이여야 합니다.") @Pattern(regexp = ".*(?=.{4,})(?=.*[\\d[a-z][A-Z]]{4,}).*", message = "최소 4 자리 / 알파벳 문자가 필요합니다.") private String username; // 아이디 unique @NotBlank(message="닉네임은 필수 입니다.") @Pattern(regexp="^[ㄱ-ㅎ가-힣]*$", message="이름은 한글만 가능합니다.") private String nickname; //닉네임 @NotNull(message="비밀번호는 필수 입니다.") @Size(min=6, max=20, message="비밀번호는 6-20자 사이여야 합니다.") @Pattern(regexp="([0-9].*[!,@,#,^,&,*,(,)])|([!,@,#,^,&,*,(,)].*[0-9])", message="비밀번호는 숫자, 특수문자가 포함되어야 합니다.") private String password; //패스워드 private String pwCheck; @NotBlank(message="이메일은 필수 입니다.") @Pattern(regexp="\\w+[@]\\w+\\.\\w+", message="이메일 형식에 맞지 않습니다.") private String email; //이메일 private Integer enabled; // 계정사용여부 @NotBlank(message="포인트는 필수 입니다.") @Pattern(regexp="^[0-9]*$", message="양수만 가능합니다.") private String upoint; // 포인트 private Timestamp regdate; // 현재 날짜 public int getIdx() { return idx; } public void setIdx(int idx) { this.idx = idx; } //비밀번호 체크 public boolean passwordCheck() { return password.equals(pwCheck); } ~~setter, getter, toString() 생략 }
UsersJoinController
컨트롤
/** * <pre> * 1. 패키지명 : net.macaronics.web.controller * 2. 타입명 : MemberJoinController.java * 3. 작성일 : 2017. 12. 25. 오후 3:30:47 * 4. 저자 : 최준호 * * </pre> * */ package net.macaronics.join.controller; import javax.validation.Valid; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.util.StringUtils; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import net.macaronics.join.domain.UsersVO; import net.macaronics.join.service.UsersJoinService; @Controller @RequestMapping("/member/*") public class UsersJoinController { private static final Logger logger =LoggerFactory.getLogger(UsersJoinController.class); private static final String ViewPage="memberJoin/joinForm"; @Autowired private BCryptPasswordEncoder bCryptPasswordEncoder; @Autowired private UsersJoinService usersJoinService; @RequestMapping(value="joinForm.do", method=RequestMethod.GET) public String memberForm(UsersVO usersVO) throws Exception{ return ViewPage; } //bindResult 다음에 Model 이 와야 한다. 순서가 틀리면 에러가 발생한다. @RequestMapping(value="join.do", method=RequestMethod.POST) public String memberInsert(@ModelAttribute(name="usersVO") @Valid UsersVO usersVO, BindingResult bindResult, Model model ) throws Exception{ if(bindResult.hasErrors()) { return ViewPage; } //username 중복 체크 if(usersJoinService.usersNameCheck(usersVO.getUsername())) { // 0보다 크면 중복이 존재 true 반환 logger.info("중복된 아이디 입니다."); model.addAttribute("idCheck", "중복된 아이디 입니다." ); return ViewPage; } //비밀번호 체크 if(!usersVO.passwordCheck()) { logger.info("비밀번호와 비밀번호 확인이 일치하지 않습니다."); model.addAttribute("pwCheck", "비밀번호와 비밀번호 확인이 일치하지 않습니다." ); return ViewPage; } //비밀번호 암오화 작업 if(StringUtils.hasText(usersVO.getPassword())) { String bCryptString=bCryptPasswordEncoder.encode(usersVO.getPassword()); usersVO.setPassword(bCryptString); } usersJoinService.usersRegister(usersVO); return "redirect:/"; } }
DAO - @Repository
/** * <pre> * 1. 패키지명 : net.macaronics.join.persistence * 2. 타입명 : UsersJoinDAOImpl.java * 3. 작성일 : 2018. 1. 1. 오후 6:11:46 * 4. 저자 : 최준호 * * </pre> * */ package net.macaronics.join.persistence; import org.apache.ibatis.session.SqlSession; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import net.macaronics.join.domain.UsersVO; @Repository public class UsersJoinDAOImpl implements UsersJoinDAO { private static final String namespace = "net.macaronics.mapper.joinMapper."; @Autowired private SqlSession sqlSession; public Integer usersNameCheck(String username) throws Exception { return sqlSession.selectOne(namespace+"usersNameCheck", username); } //등록 @Override public void usersRegister(UsersVO usersVO) { sqlSession.insert(namespace+"usersRegister", usersVO); } }
joinMapper.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="net.macaronics.mapper.joinMapper"> <select id="usersNameCheck" resultType="int" > select count(*) from USERS WHERE username =#{username} </select> <insert id="usersRegister" > INSERT INTO USERS(username, nickname , password, email, upoint ) VALUES(#{username} , #{nickname} , #{password} , #{email} , 1) </insert> </mapper>
서비스
/** * <pre> * 1. 패키지명 : net.macaronics.join.service * 2. 타입명 : UsersJoinServiceImpl.java * 3. 작성일 : 2017. 12. 27. 오후 11:09:09 * 4. 저자 : 최준호 * * </pre> * */ package net.macaronics.join.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import net.macaronics.join.domain.UsersVO; import net.macaronics.join.persistence.UsersJoinDAO; @Service public class UsersJoinServiceImpl implements UsersJoinService { @Autowired private UsersJoinDAO usersJoinDAO; // usersname 중복 체크 @Override public boolean usersNameCheck(String username) throws Exception { boolean isCheck=false; int check=usersJoinDAO.usersNameCheck(username); // 0보다 크면 중복이 존재 true 반환 if(check>0) { isCheck=true; }else { // 0이면 중복 없음. isCheck=false; } return isCheck; } //등록 @Override public void usersRegister(UsersVO usersVO) throws Exception { usersJoinDAO.usersRegister(usersVO); } }
뷰 - joinForom.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="form" uri="http://www.springframework.org/tags/form"%> <!DOCTYPE html> <html lang="ko"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 위 3개의 메타 태그는 *반드시* head 태그의 처음에 와야합니다; 어떤 다른 콘텐츠들은 반드시 이 태그들 *다음에* 와야 합니다 --> <title>회원 가입</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css"> <!-- 부가적인 테마 --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css"> <!-- 합쳐지고 최소화된 최신 자바스크립트 --> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script> <script src="//code.jquery.com/jquery.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> <!-- IE8 에서 HTML5 요소와 미디어 쿼리를 위한 HTML5 shim 와 Respond.js --> <!-- WARNING: Respond.js 는 당신이 file:// 을 통해 페이지를 볼 때는 동작하지 않습니다. --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> </head> <body> <h1 class="text-center">회원 가입</h1> <div class="row"> <div class="col-xs-3 col-sm-3"></div> <div class="col-xs-6 col-sm-6"> ' <form:form method="post" commandName="usersVO" action="/member/join.do"> <table class="table"> <tr> <td class="primary">아이디</td> <td><form:input path="username" cssClass="form-control" /> <br> <form:errors path="username" cssClass="label label-danger" /> <br> <span class="label label-danger">${idCheck}</span> </td> </tr> <tr> <td class="primary">비밀번호</td> <td><form:password path="password" cssClass="form-control" /> <br> <form:errors path="password" cssClass="label label-danger" /> </td> </tr> <tr> <td class="primary">비밀번호확인</td> <td><input type="password" name="pwCheck" class="form-control"> <br> <span class="label label-danger">${pwCheck}</span></td> </tr> <tr> <td class="primary">닉네임</td> <td><form:input path="nickname" cssClass="form-control" /> <br> <form:errors path="nickname" cssClass="label label-danger" /></td> </tr> <tr> <td class="primary">이메일</td> <td><form:input path="email" cssClass="form-control" /> <br> <form:errors path="email" cssClass="label label-danger" /> </td> </tr> <tr> <td class="primary">포인트</td> <td><form:input path="upoint" cssClass="form-control" /> <br> <form:errors path="upoint" cssClass="label label-danger" /> </td> </tr> <tr class="text-center"> <td colspan="2"><input type="submit" value="회원가입" class="btn btn-success"> </td> </tr> </table> </form:form> </div> </div> </body> </html>
제작 : macaronics.net - Developer Jun Ho Choi
소스 : https://github.com/braverokmc79/spring_simple_blog/commits/master
댓글 ( 5)
댓글 남기기