common.html footer를 수정해줍니다.
JavaScript와 JQuery를 사용할 수 있게해줍니다.
<footer th:fragment="footer">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-Fy6S3B9q64WdZWQUiU+q4/2Lc9npb8tCaSX9FK7E8HnRr0Jz8D6OP9dO5Vg3Q9ct"
crossorigin="anonymous"></script>
</footer>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
script 부분 수정
<script>
function deleteBoard(id) {
//DELETE /api/boards/{id}
if(!confirm("게시글을 삭제하시겠습니까?")){
return;
}
$.ajax({
type: 'DELETE',
url: '/api/boards/' + id,
success: function(result) {
console.log('result', result);
alert('삭제됐습니다.');
//삭제 성공시 요청될 url
location.href = '/board/list';
}
});
}
</script>
"게시글을 삭제하시겠습니까?" 부분에서 확인을 누르면 삭제됐습니다 창이 나오고 게시글은 삭제 후 게시글 list 부분으로 이동을 합니다. 반대로 삭제 여부를 묻는 부분에서 취소를 누르게 되면 현재창에 그대로 머물게 됩니다.
<button type="button" class="btn btn-primary"
sec:authorize="hasRole('ROLE_ADMIN')" th:onclick="|deleteBoard(*{id})|">삭제</button>
type을 button으로 수정해줍니다.
현재 글 작성시 WhiteLabel Error가 발생하게 됩니다. 이를 수정하기 위해
form.html에 확인 버튼에서 null값을 가지지 않은 경우에만 수행하도록 코드를 수정해줍니다.
<button type="submit" class="btn btn-primary" th:if="${board != null and board.user != null and #authentication.name == board.user.username}">확인</button>
register.html 수정
th:required="true" 속성을 지정하여 필수 입력 필드로 만들어줍니다.
<div class="form-floating">
<label for="username">Username</label>
<input type="text" class="form-control" id="username" name="username" placeholder="Username" th:required="true">
<p th:if="${usernameError}" th:text="${usernameError}" style="color:red"></p>
</div>
<div class="form-floating">
<label for="password1">비밀번호</label>
<input type="password" class="form-control" id="password1" name="password1" placeholder="Password" th:required="true">
</div>
<div class="form-floating">
<label for="password2">비밀번호 확인</label>
<input type="password" class="form-control" id="password2" name="password2" placeholder="Password" th:required="true">
<p th:if="${passwordError}" th:text="${passwordError}" style="color:red"></p>
</div>
아이디 중복 확인을 위해 UserService와 UserRepository를 수정해줍니다.
public boolean checkUserName(String username){
return userRepository.existsByUsername(username);
}
boolean existsByUsername(String username);
AccountController에서 아이디 중복체크와 비밀번호와 비밀번호 확인이 일치하는지 체크해줍니다.
@PostMapping("/register")
public String register(User user, @RequestParam String username, @RequestParam String password1, @RequestParam String password2, Model model){
if (userService.checkUserName(username)) {
model.addAttribute("usernameError", "이미 사용 중인 아이디입니다.");
return "account/register";
}
if(!password1.equals(password2)){
model.addAttribute("passwordError", "비밀번호가 일치하지 않습니다.");
return "account/register";
}
userService.save(user);
return "redirect:/";
}
user테이블에 있는 아이디로 회원가입을 시도하면 이미 사용 중인 아이디라고 뜹니다.
비밀번호도 맞지 않으면 오류 메시지가 뜨게 됩니다.
현재 글 작성자가 작성한 게시글을 다른 사용자가 삭제할 수 있는 기능적 오류가 있습니다. 이를 수정해줍니다.
ROLE_ADMIN 권한을 가지고 있거나 게시글 작성자의 이름과 현재 로그인한 사용자의 이름이 같은 경우에만 삭제버튼이 표시되게 설정해줍니다.
<button th:if="${board.title != null and (#authorization.expression('hasAuthority(''ROLE_ADMIN'')') or (board.user != null and
#authentication.name == board.user.username))}" type="button" class="btn btn-primary" th:onclick="|deleteBoard(*{id})|">삭제</button>
제목이 없을 경우에는 삭제 버튼이 표시되지 않게 해주었습니다. 이러한 코드를 넣은 이유는 새로운 글을 작성할 때도 삭제 버튼이 표시되는 것을 막아주기 위해서입니다.
글 작성 시
자신의 글 or 관리자가 게시글을 볼 경우
일반 사용자가 다른 사용자의 게시글을 볼 경우
하지만 이 코드는 api를 직접 호출할 경우 게시글이 삭제될 수 있습니다. 이를 막기 위해서 코드를 수정해줍니다.
BoardApiController.java
@PreAuthorize("hasRole('ADMIN') or #board.user.username == authentication.name")
@DeleteMapping("/boards/{id}")
void deleteBoard(@PathVariable Long id) {
boardRepository.deleteById(id);
}
@preauthorize란
Spring Security에서 제공하는 어노테이션으로 메소드 수준의 보안을 제공합니다.
회원가입 오류 수정
AccountController.java
@PostMapping("/register")
public String register(@RequestParam String username, @RequestParam String password1, @RequestParam String password2, Model model){
if (userService.checkUserName(username)) {
model.addAttribute("usernameError", "이미 사용 중인 아이디입니다.");
return "account/register";
}
if(!password1.equals(password2)){
model.addAttribute("passwordError", "비밀번호가 일치하지 않습니다.");
return "account/register";
}
User user = new User();
user.setUsername(username);
user.setPassword(password1);
userService.save(user);
return "redirect:/";
}