(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";

}

 

위와 같이 이미 구현된 회원가입 과정도 수정을 계획중이다.

또한, 코드관련 영상들을 시청하다가 예외처리란 것을 알게되어, 회원가입 코드 수정 이후에 비로그인 시 접근 불가한 페이지를 설정할 예정이다.

 

 

 

 

+ Recent posts