이 예제에는 스프링 시큐리티와 Thymeleaf가 사용되었습니다.
기초적인 데이터베이스 insert 예제로, 특별한 내용은 없고 다음을 연습하기 위해 만들었습니다.
- 회원 테이블에 비밀번호를 BCrypt로 해싱한 텍스트를 입력
- 원칙적으로 입력한 값에 대한 유효성 검사는 프론트엔드 측과 백엔드 측 모두에서 행해져야 하는데, 백엔드 측의 유효성 검사 과정을 추가
시간 관계상 프론트엔드 측 유효성 검사는 구현하지 않았습니다.
@GetMapping
과 @PostMapping
은 기존의 @RequestMapping
을 GET 방식 또는 POST 방식으로 지정할 수 있습니다. @PostMapping("/url")
은 @RequestMapping(value="/url", method=RequestMethod.POST)
과 동일한 기능을 합니다.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>회원가입</title> | |
<link rel="stylesheet" type="text/css" th:href="@{/webjars/bootstrap/4.4.1/css/bootstrap.css}"> | |
<link rel="stylesheet" type="text/css" href="/board.css"> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="py-5 text-center"> | |
<img class="d-block mx-auto mb-4" src="https://getbootstrap.com/docs/4.0/assets/brand/bootstrap-solid.svg" alt="" width="72" height="72"> | |
<h2>회원가입 결과 여부</h2> | |
<pre th:text="${resultMsg}"></pre> | |
<p> | |
<a href="" th:unless="${isSuccess}">회원가입 다시하기</a> | |
<a href="/" th:if="${isSuccess}">홈페이지로 돌아가기</a> | |
</p> | |
</div> | |
</div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>회원가입</title> | |
<link rel="stylesheet" type="text/css" th:href="@{/webjars/bootstrap/4.4.1/css/bootstrap.css}"> | |
<link rel="stylesheet" type="text/css" href="/board.css"> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="py-5 text-center"> | |
<img class="d-block mx-auto mb-4" src="https://getbootstrap.com/docs/4.0/assets/brand/bootstrap-solid.svg" alt="" width="72" height="72"> | |
<h2>회원가입</h2> | |
<p class="lead">회원가입하세요. 가입하면 게시판을 열람할 수 있습니다.</p> | |
</div> | |
<div class="col-md-12 order-md-1"> | |
<h4 class="mb-3">회원정보</h4> | |
<form class="needs-validation" novalidate th:action="@{/signup}" method="POST"> | |
<div class="mb-3"> | |
<label for="username">아이디 (username)</label> | |
<div class="input-group"> | |
<div class="input-group-prepend"> | |
<span class="input-group-text">@</span> | |
</div> | |
<input type="text" class="form-control" id="username" placeholder="Username" required name="user-id"> | |
<div class="invalid-feedback" style="width: 100%;">Your username is required.</div> | |
</div> | |
</div> | |
<div class="mb-3"> | |
<label for="password">비밀번호</label> | |
<input type="password" class="form-control" id="password" placeholder="" value="" required name="user-password"> | |
<div class="invalid-feedback">유효한 비밀번호가 필요합니다.</div> | |
</div> | |
<div class="mb-3"> | |
<label for="firstName">이름</label> | |
<input type="text" class="form-control" id="real-name" placeholder="" value="" required name="user-real-name"> | |
<div class="invalid-feedback">유효한 이름을 입력해야합니다.</div> | |
</div> | |
<div class="mb-3"> | |
<label for="email">이메일</label> | |
<input type="email" class="form-control" id="email" placeholder="you@example.com" name="user-email"> | |
<div class="invalid-feedback">올바른 이메일을 입력하세요.</div> | |
</div> | |
<div class="mb-3"> | |
<label for="address">좋아하는 음식</label> <input type="text" class="form-control" id="food" placeholder="예) 치킨" required name="user-food"> | |
<div class="invalid-feedback">좋아하는 음식을 입력하세요.</div> | |
</div> | |
<hr class="mb-4"> | |
<button class="btn btn-primary btn-lg btn-block" type="submit">가입하기</button> | |
<hr class="mb-4"> | |
<footer th:replace="/fragments/semantic :: footer"></footer> | |
</form> | |
</div> | |
</div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.springboot.security.dao; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.jdbc.core.JdbcTemplate; | |
import org.springframework.stereotype.Repository; | |
@Repository | |
public class SimpleUserDAO { | |
@Autowired JdbcTemplate jt; | |
public List<Map<String, ?>> getUserInfo(String username) { | |
return jt.query("select * from simple_users where username=?", new Object[] {username} , (rs, rowNum) -> { | |
Map<String, Object> anUser = new HashMap<>(); | |
anUser.put("username", rs.getString(2)); | |
anUser.put("password", rs.getString(3)); | |
anUser.put("role", rs.getString(4)); | |
anUser.put("food", rs.getString(5)); | |
return anUser; | |
}); | |
} | |
public int insertUserInfo(Map<String, String> user) { | |
String sql = "insert into " | |
+ "simple_users(iduser, username, password, role, food, email, real_name) " | |
+ "values(0, ?, ?, 'GUEST', ?, ?, ?)"; | |
return jt.update(sql, | |
user.get("user-id"), | |
user.get("user-password"), | |
user.get("user-food"), | |
user.get("user-email"), | |
user.get("user-real-name") | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.springboot.security.controller; | |
import java.util.Map; | |
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.web.bind.annotation.GetMapping; | |
import org.springframework.web.bind.annotation.PostMapping; | |
import org.springframework.web.bind.annotation.RequestParam; | |
import com.springboot.security.dao.SimpleUserDAO; | |
@Controller | |
public class UserController { | |
@Autowired SimpleUserDAO sud; | |
@GetMapping("/signup") | |
public String signUp(Model model) { | |
return "signup/signup"; | |
} | |
@PostMapping("/signup") | |
public String signUpProc(Model model, @RequestParam Map<String, String> params) { | |
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); | |
System.out.println(params); | |
String userId = params.get("user-id"); | |
String userPwd = params.get("user-password"); | |
String userRealName = params.get("user-real-name"); | |
String userFood = params.get("user-food"); | |
// back-end validation | |
String result = ""; | |
boolean isAllValidate = true; | |
if(userId.length() < 4) { | |
result += "user-id must be at least 4 character long.\n"; | |
isAllValidate = false; | |
} | |
if(userPwd.length() < 4) { | |
result += "user-password must be at least 4 character long.\n"; | |
isAllValidate = false; | |
} | |
if(userRealName.length() <= 0) { | |
result += "user-name is not entered.\n"; | |
isAllValidate = false; | |
} | |
if(userFood.length() <= 0) { | |
result += "user-food is not entered.\n"; | |
isAllValidate = false; | |
} | |
// submit to database | |
if(isAllValidate) { | |
params.remove("_csrf"); | |
params.put("user-password", passwordEncoder.encode(userPwd)); | |
try { | |
int insertResult = sud.insertUserInfo(params); | |
if(insertResult >= 1) { | |
result += "You have successfully registered."; | |
} else { | |
result += "Sign-up failed. There may be duplicate information or other issues."; | |
isAllValidate = false; | |
} | |
} catch(Exception e) { | |
e.printStackTrace(); | |
result += "Sign-up failed. There may be duplicate information or other issues."; | |
isAllValidate = false; | |
} | |
} | |
model.addAttribute("isSuccess", isAllValidate); | |
model.addAttribute("resultMsg", result); | |
return "signup/signup-result"; | |
} | |
} |
0개의 댓글