SQL 확인을 위한 application.properties설정
# 기존 코드 ..............
# 개발할 때에만 create-drop 또는 update를 사용하고 운영 환경에서는 validate를 사용합니다.
spring.jpa.hibernate.ddl-auto=create-drop
# 개발시 SQL 로깅을 하여 어떤 값으로 어떤 SQL이 실행되는지 확인합니다.
spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
프론트엔드 라이브러리
- Tagify
- npm install @yaireo/tagify
- 예제) https://yaireo.github.io/tagify/
관심 주제 화면을 요청하기위한 핸들러 작성
package me.weekbelt.studyolle.settings;
@RequiredArgsConstructor
@Controller
public class SettingsController {
// 기존 코드 ............
@GetMapping("/settings/tags")
public String updateTags(@CurrentUser Account account, Model model) {
model.addAttribute(account);
return "settings/tags";
}
}
fragments.html에 tagify추가
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head th:fragment="head">
<meta charset="UTF-8">
<title>StudyOlle</title>
<link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css"/>
<link rel="stylesheet" href="/node_modules/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="/node_modules/@yaireo/tagify/dist/tagify.css"> // 추가
<script src="/node_modules/jdenticon/dist/jdenticon.min.js"></script>
<script src="/node_modules/jquery/dist/jquery.min.js"></script>
<script src="/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<style>
.container {
max-width: 100%;
}
// 추가
.tagify--outside{
border: 0;
padding: 0;
margin: 0;
}
</style>
</head>
// 기존 코드 .........
</html>
settings/tags.html 생성
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<!--head-->
<head th:replace="fragments.html::head"></head>
<body class="bg-light">
<!--네비게이션 바-->
<div th:replace="fragments.html::main-nav"></div>
<div class="container">
<div class="row mt-5 justify-content-center">
<div class="col-2">
<div th:replace="fragments.html :: settings-menu(currentMenu='tags')"></div>
</div>
<div class="col-8">
<div class="row">
<h2 class="col-sm-12">관심있는 스터디 주제</h2>
</div>
<div class="row">
<div class="col-12">
<div class="alert alert-info" role="alert">
참여하고 싶은 스터디 주제를 입력해 주세요. 해당 주제의 스터디가 생기면 받을 수 있습니다.
태그를 입력하고 콤마(,) 또는 엔터를 입력하세요.
</div>
<input id="tags" type="text" name="tags" class="tagify-outside" aria-describedby="tagHelp"/>
</div>
</div>
</div>
</div>
<!-- footer -->
<div th:replace="fragments.html::footer"></div>
</div>
<script src="/node_modules/@yaireo/tagify/dist/tagify.min.js"></script>
</body>
</html>
타임리프 자바스크립트 템플릿
<script type="application/javascript" th:inline="javascript">
</script>
- https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#javascript-inlining
- Escaped: [[${variable}]]
- Unescaped: [${variable}]
- 네추럴 템플릿: /*[[${variable}]]*/null;
settings/tags.html에 tagify를 적용하기 위한 js코드 추가
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<!--head-->
<head th:replace="fragments.html::head"></head>
<body class="bg-light">
<!--네비게이션 바-->
<div th:replace="fragments.html::main-nav"></div>
// 기존 코드 .....
<script src="/node_modules/@yaireo/tagify/dist/tagify.min.js"></script>
<script type="application/javascript">
$(function () {
function tagRequest(url, tagTitle) {
$.ajax({
dataType: "json",
autocomplete: {
enabled: true,
rightKey: true,
},
contentType: "application/json; charset=utf-8",
method: "POST",
url: "/settings/tags" + url,
data: JSON.stringify({'tagTitle' : tagTitle})
}).done(function (data, status) {
console.log("${data} and status is ${status}");
});
}
function onAdd(e) {
tagRequest("/add", e.detail.data.value);
}
function onRemove(e) {
tagRequest("/remove", e.detail.data.value);
}
const tagInput = document.querySelector("#tags");
const tagify = new Tagify(tagInput, {
pattern: /^.{0,20}$/,
dropdown : {
enabled: 1, // suggest tags after a single character input
} // map tags
});
tagify.on("add", onAdd);
tagify.on("remove", onRemove);
// add a class to Tagify's input element
tagify.DOM.input.classList.add('form-control');
// re-place Tagify's input element outside of the element (tagify.DOM.scope), just before it
tagify.DOM.scope.parentNode.insertBefore(tagify.DOM.input, tagify.DOM.scope);
});
</script>
</body>
</html>
관심 주제 ajax요청을 전달할 DTO 객체 생성
package me.weekbelt.studyolle.settings.form;
@Data
public class TagForm {
private String tagTitle;
}
TagRepository 생성
package me.weekbelt.studyolle.tag;
@Transactional(readOnly = true)
public interface TagRepository extends JpaRepository<Tag, Long> {
Optional<Tag> findByTitle(String title);
}
관심 주제 등록 하는 핸들러 생성
package me.weekbelt.studyolle.settings;
@RequiredArgsConstructor
@Controller
public class SettingsController {
// 기존 코드 .......
private final TagRepository tagRepository;
// 기존 코드 .......
@ResponseBody
@PostMapping("/settings/tags/add")
public ResponseEntity<?> addTag(@CurrentUser Account account, @RequestBody TagForm tagForm) {
String title = tagForm.getTagTitle();
Tag tag = tagRepository.findByTitle(title).orElseGet(
() -> tagRepository.save(Tag.builder().title(tagForm.getTagTitle())
.build()));
accountService.addTag(account, tag);
return ResponseEntity.ok().build();
}
}
태그를 추가하는 addTag메소드 작성
package me.weekbelt.studyolle.account;
@Transactional
@RequiredArgsConstructor
@Service
public class AccountService implements UserDetailsService {
// 기존 코드 ........
public void addTag(Account account, Tag tag) {
// account엔티티는 Detached 상태 이기때문에 account를 먼저 읽어 온다
Optional<Account> byId = accountRepository.findById(account.getId());
byId.ifPresent(a -> a.getTags().add(tag));
}
}
Ajax 호출시 CSRF 토큰을 전달 하는 방법
모든 POST요청에는 CSRF토큰이 있어야 한다. AJAX요청도 마찬가지이다.
따라서 AJAX요청에도 CSRF토큰을 전송해야 한다.
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<!--head-->
<head th:replace="fragments.html::head"></head>
<body class="bg-light">
<!--네비게이션 바-->
<div th:replace="fragments.html::main-nav"></div>
// 기존 코드 .......
// 추가
<script type="application/javascript" th:inline="javascript">
$(function () {
const csrfToken = /*[[${_csrf.token}]]*/ null;
const csrfHeader = /*[[${_csrf.headerName}]]*/ null;
$(document).ajaxSend(function (e, xhr, options) {
xhr.setRequestHeader(csrfHeader, csrfToken);
})
});
</script>
<script type="application/javascript">
// 기존 코드 .......
</script>
</body>
</html>
이 로직을 추가하면 AJAX요청시 csrf토큰을 같이 포함해서 요청하게 된다.
참고 : https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-JPA-%EC%9B%B9%EC%95%B1#
'스프링과 JPA 기반 웹 어플리케이션 개발 > 2부(관심 주제와 지역 정보)' 카테고리의 다른 글
37. 관심 주제 자동완성 (0) | 2020.04.22 |
---|---|
36. 관심 주제 삭제 (0) | 2020.04.22 |
35. 관심 주제 조회 (0) | 2020.04.22 |
33. 관심 주제 도메인 (0) | 2020.04.22 |
32. 관심 주제와 지역 정보 관리 기능 미리보기 (0) | 2020.04.22 |