(241231) 수정 : 원래는 프로젝트의 DB쪽은 JPA로 구현 할 생각이였지만, JOIN과 같은 복잡한 select문에서 차근차근 이해하고 넘어가고 싶어 일단은 MyBatis로 변경했다. 기존의 회원가입 및 중복확인은 JPA의 간단한 findBy, save이니 그대로 냅둘 것이고, JPA는 이 프로젝트가 끝나고 깊게 한 번 공부해보려고 한다.
(250101) 수정 : 기존 게시물 작성 시 제목 및 내용이 빈칸이여도 등록되었던 것을 각 1글자 이상의 데이터가 존재 시 등록되도록 수정 / 1차 검증은 js에서 alert로 안내 > 2차 검증은 서버에서 데이터 확인 후 데이터의 길이가 0일 경우 게시글 작성 페이지로 redirect
이 글은 유저가 로그인 후 게시글을 작성하여 DB에 게시글 정보가 등록되는 과정이 담겨있다.
게시글 작성의 경우 누가 작성하였는지 정보가 필요하기에 로그인 후 게시글 작성이 가능하게끔 만들었고,
게시글 카테고리/제목/내용을 설정 및 입력 후 작성버튼을 누르면 db에 담기게 된다.
<!-- MyBatis -->
<dependency>
<!--
https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
우선 MyBatis 의존성을 추가한다.
application.properties
#mybatis setting
mybatis.mapper-locations=classpath:mybatis/mapper/**/**.xml
mybatis.configuration.cache-enabled=false
mybatis.configuration.jdbc-type-for-null=NULL
다음으로 MyBatis의 설정인데,
mybatis.mapper-locations=classpath:mybatis/mapper/**/**.xml
> 이 설정은 MyBatis가 XML 매핑 파일들을 어디서 찾을지 지정하는 경로이다.
아래에서 추가 설명을 하겠지만, 쿼리를 날리는 xml 파일 위치를 알려주는것이다.
mybatis.configuration.cache-enabled=false
> 이 설정은 MyBatis의 캐시 기능을 비활성화 해준다.
캐시를 비활성화하면, 데이터베이스에서 항상 최신 데이터를 조회하게 하기 위함이다.
mybatis.configuration.jdbc-type-for-null=NULL
> 이 설정은 SQL에서 null값을 삽입할 때, MyBatis가 NULL을 명시적으로 지정하여 데이터 삽입을 해준다.
DB 테이블에 데이터가 null값이 들어갈수도 있는 테이블이 있으니 설정해준다.
JSP
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<textarea name="content" id="editor" rows="10" cols="80"></textarea>
게시글 작성에는 CKeditor를 사용하였다.
CKeditor를 사용하기 위해서는 직접 사이트로 가서 파일을 다운받아 압출을 푼 뒤에 static 파일에 넣어 사용해도 되고,
<script src="https://cdn.ckeditor.com/ckeditor5/37.1.0/classic/ckeditor.js"></script>
cdn을 이용하여 사용해도 된다.
나는 basic 무료판 파일을 다운받아 사용하였다.
여기서 팁이 있는데, 무료판을 사용하면 아래와 같이 경고창이 뜬다.
무료버전은 더 이상 보안관련 하여 지원을 하지 않아서 뜨는 경고창인데
css로 해당 경고창을 무시할 수 있다
.cke_notifications_area {
display: none;
}
저 경고창의 class가 .cke_notification_area라서 display:none;을 하면 더 이상 안나온다
게시글 입력 폼을 완성해줬다.
여기서 서버로 보낼 데이터는 카테고리, 제목, 내용이다.
Controller Class
@Controller
@RequiredArgsConstructor
public class ImPostController {
private final ImWritePostService imWritePostService;
//글 작성 페이지로 가기
@GetMapping("/writePost")
public String writePost() {
return "post/writePost";
}
//내가 쓴 글 보기
@GetMapping("/myPost")
public String myPost() {
return "post/myPost";
}
//작성한 글 등록하기
@PostMapping("/writePost/save")
public String writePostSave(HttpSession session,
@RequestParam String category, @RequestParam String title,
@RequestParam String content){
return imWritePostService.writePostSave(session, category, title, content);
}
}
게시글 데이터(form/post)를 보내고,
//작성한 글 등록하기
@PostMapping("/writePost/save")
public String writePostSave(HttpSession session,
@RequestParam String category, @RequestParam String title,
@RequestParam String content){
return imWritePostService.writePostSave(session, category, title, content);
}
게시글 작성 관련 서비스클래스로 게시글 등록(db)할 때 필요한 데이터를 보내주었다.
Service Class
@Service
@RequiredArgsConstructor
public class ImWritePostService {
private final ImPostMapper imPostMapper;
public String writePostSave(HttpSession session, String category, String title, String content) {
//만약 제목 길이가 100 초과거나 0이면 리턴
if(title.length() > 100 || title.length() == 0) {
return "redirect:/writePost";
}
//만약 내용의 길이가 0이면 리턴
if(content.length() == 0) {
return "redirect:/writePost";
}
//만약 카테고리가 이상한 카테고리면 리턴
if(!category.equals("누구야") && !category.equals("이렇게 살아왔어") && !category.equals("고민이 있어") &&
!category.equals("숨겨둔 비밀") && !category.equals("자유게시판")) {
return "redirect:/writePost";
}
//만약 로그인 상태가 아니라면
if(session.getAttribute("userCode")==null) {
return "redirect:/writePost";
}
imPostMapper.writePost(category, title, content, (String)session.getAttribute("userCode"));
return "redirect:/myPost";
}
}
서비스 클래스에서는 관리자 도구를 통해 데이터를 변경하여 게시글 작성 가이드라인을 위반할 경우가 있으니 검사하는 과정을 만들어주었는데,
//만약 제목 길이가 100 초과거나 0이면 리턴
if(title.length() > 100 || title.length() == 0) {
return "redirect:/writePost";
}
//만약 내용의 길이가 0이면 리턴
if(content.length() == 0) {
return "redirect:/writePost";
}
1. 만약 제목이 100자 초과거나 없으면 게시글 작성 페이지로 다시 돌아간다.
2. 내용이 없으면 게시글 작성 페이지로 다시 돌아간다.
//만약 카테고리가 이상한 카테고리면 리턴
if(!category.equals("누구야") && !category.equals("이렇게 살아왔어") && !category.equals("고민이 있어") &&
!category.equals("숨겨둔 비밀") && !category.equals("자유게시판")) {
return "redirect:/writePost";
}
2. 만약 정해진 카테고리 외에 값이 들어온다면 게시글 작성 페이지로 다시 돌아간다.
//만약 로그인 상태가 아니라면
if(session.getAttribute("userCode")==null) {
return "redirect:/writePost";
}
3. 만약 로그인 상태가 아니라면 게시글 작성 페이지로 다시 돌아간다.
위 세가지의 검사를 진행하고 별 문제가 없다면 해당 게시글은 등록되는 절차를 진행하게 된다.
(서버에서도 2차 검증을 실시한 이유는 마지막에 써놓았다)
imPostMapper.writePost(category, title, content, (String)session.getAttribute("userCode"));
return "redirect:/myPost";
imPostMapper.writePost(category, title, content, (String)session.getAttribute("userCode"));
mapper 클래스를 게시글작성 기능을 추가해주었다.
Mapper Interface
@Mapper
public interface ImPostMapper {
//게시글 작성 db에 insert
void writePost(String category, String title, String content, String userCode);
}
Mapper Interface는 MyBatis에서 데이터베이스와의 상호작용을 정의하는 역할을 한다. @Mapper 어노테이션을 사용하여 MyBatis가 이 인터페이스를 Mapper로 인식하게되며, 인터페이스 내의 메서드들이 SQL 문과 연결되어 데이터베이스 작업을 수행하게 된다.
직접 쿼리문을 날리는 것은 xml 파일이지만 쿼리문에 where절에 필요한 값을 전달해주는 역할이라고 이해하면 될 것 같다.
Mapper.xml
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tech.im.mapper.ImPostMapper">
<!-- 게시글 작성 insert -->
<insert id="writePost">
INSERT INTO
IM_POST(POST_CATEGORY, POST_TITLE, POST_CONTENT, POST_USERCODE)
VALUES(#{category}, #{title}, #{content}, #{userCode})
</insert>
</mapper>
위에서 말한 직접 쿼리를 날리는 xml 파일이다.
<mapper namespace="com.tech.im.mapper.ImPostMapper">
현재 이 xml과 Mapper Interface와 연결해준 것이다.
<insert id="writePost">
현재 이 파일과 연결된 메소드를 뜻하는데, Mapper Interface(위에 설명한 인터페이스)에 있는 writePost 메소드와 연결된거다.
INSERT INTO
IM_POST(POST_CATEGORY, POST_TITLE, POST_CONTENT, POST_USERCODE)
VALUES(#{category}, #{title}, #{content}, #{userCode})
이렇게 쿼리문을 날려 내가 원하는 데이터를 불러온다
where절에 필요한 값은 앞서 설명했듯이 Mapper Interface에 메소드로 받은 파라미터 값들을
#{} 안에 넣어줘 완성시켜준다. 이때 변수명과 일치 시켜야한다.
결과
게시글이 정상적으로 DB에 저장된 것을 확인했다.
해당 이미지 캡쳐 후 바로 또 새로운 게시글을 작성을 해보았는데, 정상적으로 새로운 게시글로 DB에 저장된 것을 확인 할 수 있었다.
이번 글을 작성하면서 솔직히 제일 놀랐던것은, 갑자기 어릴적에 관리자도구를 통해 네이버 view에 나오는 글들을 바꿔서 놀았던게 생각나서 혹시나 내 프로젝트도 관리자도구로 변경이 가능할까?싶어 시도해봤는데, jsp에서 설정된거나 js에서 설정된(게시글 작성 시 제목은 100자 이하로 설정) 값을 변경해서 데이터를 서버로 보낼 수 있던 문제가 있었다.
그래서 서버에서도 데이터 검사를 추가해주는 과정을 추가하여 보완했다.
인터넷에 검색하여 찾아보니 클라이언트(JSP나 JS)에서 검증을 진행하고 서버에서도 또 검증을 한다고 한다.
아직도 나는 모르는게 너무 많지만 하나하나 알아가는게 너무 재미있다...
//만약 제목 길이가 100 초과면 리턴
if(title.length()>100) {
return "redirect:/writePost";
}
//만약 카테고리가 이상한 카테고리면 리턴
if(!category.equals("who") && !category.equals("life") && !category.equals("worry") &&
!category.equals("secret") && !category.equals("free")) {
return "redirect:/writePost";
}
위와 같이 이미 구현된 회원가입 과정도 수정을 계획중이다.
또한, 코드관련 영상들을 시청하다가 예외처리란 것을 알게되어, 회원가입 코드 수정 이후에 비로그인 시 접근 불가한 페이지를 설정할 예정이다.
'개인프로젝트 > I'm' 카테고리의 다른 글
Spring 게시글 페이징 기능 (1) | 2025.01.01 |
---|---|
Spring HandlerInterceptor 비로그인 시 페이지 진입이 불가한 페이지 설정 (0) | 2024.12.29 |
Spring 회원가입 후 로그인/로그아웃 HttpSession 적용 (0) | 2024.12.27 |
Spring JPA 회원가입 + 비밀번호 암호화 Spring security(+회원 UUID 고유코드 생성)(241229 서버 2차 조건 검증 기능 추가) (0) | 2024.12.24 |
Spring 회원가입 시 인증번호 일치 여부 확인 / redis 사용 (2) | 2024.12.21 |