티스토리 뷰

[ URL설계 ]

 - forumSlug를 이용해 게시판을 구분한다.

 - 처음엔 post 등록, 삭제, 변경은 {forumSlug}를 빼고 구현할까 했지만 등록의 경우 어느 게시판에 게시글을 작성하는지에 대한 정보가 필요하다. 조회의 경우 조회가 끝난 뒤 목록으로 돌아가거나 게시판 내의 다른 게시물 리스트를 보여줄 때 게시판에 대한 정보가 필요하다. 삭제, 변경 등은 각 요청을 처리한 뒤 게시판으로 돌아가야 되는데, 이때 게시판에 대한 정보가 필요하다. 그래서 모두 forumSlug를 URI에 추가하게 되었다.

 

 GET /posts/{forumSlug}/{postNumber} : post 조회

 GET /posts/{forumSlug} : post list 조회

 GET /posts/{forumSlug}/registration : post 등록 양식

 POST /posts/{forumSlug} : post 등록 요청

 PATCH /posts/{forumSlug}/{postNumber} : post 내용 변경

 DELETE /posts/{forumSlug}/{postNumber} : post 삭제

 

 

[ 고민 ]

 - 게시글을 등록할 때 writer를 사용자 아이디로 하는 게 좋을지, 사용자 닉네임으로 하는 게 좋을지 모르겠다. 이렇게 생각해보니 애초에 writer란 말도 애매하다. writer가 userNumber를 의미하는지, userId를 의미하는지, userNickname을 의미하는지 알 수가 없다. 그런데 이미 nickname이라 간주하고 구현했다. 일단은 이렇게 해두고 나중에 다시 손봐야겠다.

 - 아이디나 닉네임을 바꾸는 기능을 추가했을 때 생각해봤다. 처음엔 이런 기능을 추가했을 때 어떤 문제가 생기지 않을까 걱정했는데, DB엔 posts 필드가 userNumber로 되어 있어서 바뀌어도 상관없다. 프런트 관점, DB 관점, Service 관점 등을 돌아가면서 생각하다 보니 조금 헷갈린다.

 - post 조회 화면에서 변경, 삭제 요청 버튼을 이용해서 이동을 한다. 그럼 조회할 때 PostVO를 보내주니까 조회 화면 상에 있을 땐 PostVO에 대한 정보를 가지고 있고 따라서 postNumber 정보도 가지고 있다. 첫 구현이라 그런지 이 사실을 깜빡한다.

 

 

[ DB Table and Sequence ]

create table posts (
    post_number number(20) primary key,
    forum_number number(20) references forums(forum_number) on delete set null,
    post_title varchar2(100) not null,
    post_content varchar2(2000) not null,
    post_writer number(20) references users(user_number) on delete cascade,
    date_posted date default sysdate not null,
    date_post_modified date,
    post_views_count number(20) default 0 not null
);

create sequence seq_post;

 

 

[ PostVO ]

@Data
public class PostVO {

	private Long number;
	private Long forumNumber;
	
	private String title;
	private String content;
	private String writer;
	
	private Date datePosted;
	private Date dateModified;
	
	private Long views;
}

 

 

[ PostMapper Interface and Impl ]

public interface PostMapper {
	
	public int insertPost(PostVO post);
	
	public PostVO readPostByPostNumber(Long postNumber);
	
	public List<PostVO> readPostsByForumNumber(@Param("forumNumber") Long forumNumber, @Param("from") Long from, @Param("to") Long to);
	
	public long readTotalPostsCountByForumNumber(Long forumNumber);
	
	public int updatePost(PostVO post);
	
	public int increasePostViewsByPostNumber(Long postNumber);
	
	public int deletePostByPostNumber(Long postNumber);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bibidi.mapper.PostMapper">
	
	<resultMap type="com.bibidi.domain.PostVO" id="postMap">
		<id property="number" column="forum_number"/>
		<result property="number" column="post_number"/>
		<result property="forumNumber" column="forum_number" />
		<result property="title" column="post_title" />
		<result property="content" column="post_content" />
		<result property="writer" column="user_nickname" />
		<result property="datePosted" column="date_posted" />
		<result property="dateModified" column="date_post_modified" />
		<result property="views" column="post_views_count" />
	</resultMap>
	
	<insert id="insertPost">
		INSERT INTO posts 
			(post_number, forum_number, post_title, post_content, post_writer)
		VALUES
			(seq_post.nextval, #{forumNumber}, #{title}, #{content}, 
			(SELECT user_number FROM users WHERE user_nickname = #{writer}))
	</insert>
	
	<select id="readPostByPostNumber" resultMap="postMap">
		SELECT post_number, forum_number, post_title, post_content, user_nickname, date_posted, date_post_modified, post_views_count
		FROM posts
		INNER JOIN users ON user_number = post_writer
		WHERE post_number = #{postNumber}
	</select>
	
	<select id="readPostsByForumNumber" resultMap="postMap">
		<![CDATA[
			SELECT post_number, post_title, user_nickname, date_posted, post_views_count 
			FROM
				(SELECT ROWNUM rn, post_number, post_title, user_nickname, date_posted, post_views_count 
				FROM 
					(
						SELECT post_number, post_title, user_nickname, date_posted, post_views_count
						FROM posts
						INNER JOIN users ON post_writer = user_number
						WHERE forum_number = #{forumNumber}
						ORDER BY post_number DESC
					)
				WHERE ROWNUM <= #{to}
				)
			WHERE rn >= #{from}
		]]>
	</select>
	
	<select id="readTotalPostsCountByForumNumber" resultType="long">
		SELECT count(*) FROM posts
		WHERE forum_number = #{forumNumber}
	</select>
	
	<update id="updatePost">
		UPDATE posts SET
			post_title = #{title},
			post_content = #{content},
			date_post_modified = sysdate
		WHERE post_number = #{number}
	</update>
	
	<update id="increasePostViewsByPostNumber">
		UPDATE posts SET
			post_views_count = post_views_count + 1
		WHERE post_number = #{postNumber}
	</update>
	
	<delete id="deletePostByPostNumber">
		DELETE FROM posts
		WHERE post_number = #{postNumber}
	</delete>
</mapper>

 

 

 

[ PostMapper Tests ]

@RunWith(SpringRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j
public class PostMapperTests {

	@Setter(onMethod_ = @Autowired)
	private PostMapper postMapper;
	
	
	@Test
	public void testInsertPost() {
		
		PostVO post = new PostVO();
		post.setForumNumber(1L);
		post.setTitle("new title");
		post.setContent("new content");
		post.setWriter("bibidi");
		
		log.info("THE NUMBER OF INSERTED POSTS : " + postMapper.insertPost(post));
	}
	
	@Test
	public void testReadPostByPostNumber() {
		
		log.info(postMapper.readPostByPostNumber(1L));
	}
	
	@Test
	public void testReadPostsByForumNumber() {
		
		postMapper
			.readPostsByForumNumber(1L, 1L, 10L)
			.forEach(post -> log.info(post));
	}
	
	@Test
	public void testReadTotalPostsCountByForumNumber() {
		
		log.info("THE TOTAL COUNT OF POSTS : " + postMapper.readTotalPostsCountByForumNumber(1L));
	}
	
	@Test
	public void testUpdatePost() {
		PostVO post = new PostVO();
		post.setNumber(1L);
		post.setTitle("updated title");
		post.setContent("updated content");
		
		log.info("THE NUMBER OF UPDATED POSTS : " + postMapper.updatePost(post));
	}
	
	@Test
	public void testIncreasePostViewsByPostNumber() {
		Long postNumber = 1L;
		log.info("THE NUMBER OF POSTS WHOSE VIEWS INCREASED : " + postMapper.increasePostViewsByPostNumber(postNumber));
	}
	
	@Test
	public void testDeletePostByPostNumber() {
		log.info("THE NUMBER OF DELETED POSTS : " + postMapper.deletePostByPostNumber(2L));
	}
}

 

 

[ PostService Interface and Impl ]

public interface PostService {

	public int registerPost(PostVO post);
	
	public PostVO getPostByPostNumber(Long postNumber);
	
	public List<PostVO> getPostsByForumSlug(String forumSlug, SearchCriteria searchCriteria);
	
	public long getTotalPostsCountByForumNumber(Long forumNumber);
	
	public int modifyPost(PostVO post);
	
	public int deletePostByPostNumber(Long postNumber);
}
@Service
@Log4j
public class PostServiceImpl implements PostService{

	@Setter(onMethod_ = @Autowired)
	private PostMapper postMapper;
	
	@Setter(onMethod_ = @Autowired)
	private ForumMapper ForumMapper;
	
	@Setter(onMethod_ = @Autowired)
	private UserMapper userMapper;
	
	private static final Long SCORE = 30L;
	
	@Override
	public int registerPost(PostVO post) {
		
		log.info("register Post.............");
		
		int result = postMapper.insertPost(post);
		if (result > 0) {
			result = userMapper.increaseUserActivityScoreByUserNickname(post.getWriter(), SCORE);
		}
		
		return result;
	}

	@Override
	public PostVO getPostByPostNumber(Long postNumber) {
		
		log.info("get post by post number .............");
		
		postMapper.increasePostViewsByPostNumber(postNumber);
		return postMapper.readPostByPostNumber(postNumber);
	}

	@Override
	public List<PostVO> getPostsByForumSlug(String forumSlug, SearchCriteria searchCriteria) {
		
		log.info("get posts by forum slug..............");
		Long forumNumber = ForumMapper.readForumByForumSlug(forumSlug).getNumber();
		
		Long to = searchCriteria.getPageNumber() * searchCriteria.getContentQuantity();
		Long from = to - searchCriteria.getContentQuantity() + 1;
		
		log.info(from);
		log.info(to);
		
		return postMapper.readPostsByForumNumber(forumNumber, from, to);
	}
	
	@Override
	public long getTotalPostsCountByForumNumber(Long forumNumber) {
		
		log.info("get total posts count by forum number..................");
		
		return postMapper.readTotalPostsCountByForumNumber(forumNumber);
	}

	@Override
	public int modifyPost(PostVO post) {
		
		log.info("modify post.........................");
		return postMapper.updatePost(post);
	}

	@Override
	public int deletePostByPostNumber(Long postNumber) {
		
		log.info("delete post by post number..................");
		return postMapper.deletePostByPostNumber(postNumber);
	}

}

 - 나중에 try catch 구문을 이용하도록 고쳐야함. transaction 기능을 이용해 원자성을 가지도록 해야함.

 

[ PostService Tests ]

@RunWith(SpringRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j
public class PostServiceTests {

	@Setter(onMethod_ = @Autowired)
	private PostService postService;
	
	
	@Test
	public void testNotNull() {
		
		assertNotNull(postService);
		log.info(postService);
	}
	
	@Test
	public void testRegisterPost() {
		PostVO post = new PostVO();
		post.setForumNumber(1L);
		post.setTitle("new title");
		post.setContent("new content");
		post.setWriter("bibidi");
		
		log.info("THE NUMBER OF REGISTERED POSTS : " + postService.registerPost(post));
	}
	
	@Test
	public void testGetPostByPostNumber() {
		
		log.info(postService.getPostByPostNumber(3L));
	}
	
	@Test
	public void testGetPostsByForumSlug() {
		
		String forumSlug = "notice";
		SearchCriteria searchCriteria = new SearchCriteria(2L, 20L);
		
		log.info("searchCriteria : " + searchCriteria);
		
		postService
			.getPostsByForumSlug(forumSlug, searchCriteria)
			.forEach(post -> log.info(post));
	}
	
	@Test
	public void testModifyPost() {
		
		PostVO post = new PostVO();
		post.setNumber(2L);
		post.setTitle("updated title");
		post.setContent("updated content");
		
		log.info("THE NUMBER OF MODIFIED POSTS : " + postService.modifyPost(post));
	}
	
	@Test
	public void testDeletePostByPostNumber() {
		
		log.info("THE NUMBER OF DELETED POSTS : " + postService.deletePostByPostNumber(4L));
	}
}

 

 

[ PostController ]

@Controller
@Log4j
@RequestMapping("/posts/*")
public class PostController {
	
	@Setter(onMethod_ = @Autowired)
	private PostService postService;
	
	@Setter(onMethod_ = @Autowired)
	private ForumService forumService;
	

	@RequestMapping(value="/{forumSlug}", method=RequestMethod.GET)
	public String getPosts(@PathVariable(name = "forumSlug") String forumSlug, SearchCriteria searchCriteria, Model model) {
		
		log.info("PostController get posts.............");
		
		ForumVO forum = forumService.getForumByForumSlug(forumSlug);

		model.addAttribute("posts", postService.getPostsByForumSlug(forumSlug, searchCriteria));
		model.addAttribute("forum", forum);
		model.addAttribute("pageMaker", new Page(searchCriteria, postService.getTotalPostsCountByForumNumber(forum.getNumber())));
		
		return "posts/postList";
	}
	
	@RequestMapping(value="/{forumSlug}/{postNumber}", method=RequestMethod.GET)
	public String getPost(@PathVariable(name="forumSlug") String forumSlug, @PathVariable(name="postNumber") Long postNumber, SearchCriteria searchCriteria, Model model) {
		
		log.info("PostController get post.............");
		
		ForumVO forum = forumService.getForumByForumSlug(forumSlug);
		
		model.addAttribute("selectedPost", postService.getPostByPostNumber(postNumber));
		model.addAttribute("forum", forum);
		model.addAttribute("posts", postService.getPostsByForumSlug(forumSlug, searchCriteria));
		model.addAttribute("pageMaker", new Page(searchCriteria, postService.getTotalPostsCountByForumNumber(forum.getNumber())));
		
		return "posts/postPage";
	}
	
	@RequestMapping(value="/{forumSlug}/{postNumber}/modification", method=RequestMethod.GET)
	public String getPostModificationForm(@PathVariable("forumSlug") String forumSlug, @PathVariable("postNumber") Long postNumber, Model model) {
		
		log.info("PostController get post modification form");
		
		model.addAttribute("forum", forumService.getForumByForumSlug(forumSlug));
		model.addAttribute("post", postService.getPostByPostNumber(postNumber));
		return "posts/postModificationForm";
	}
	
	@RequestMapping(value="/{forumSlug}/registration", method=RequestMethod.GET)
	public String getPostRegistrationForm(@PathVariable("forumSlug") String forumSlug, Model model) {
		
		log.info("PostController get register form.............");
		
		model.addAttribute("forum", forumService.getForumByForumSlug(forumSlug));
		return "posts/postRegistrationForm";
	}
	
	
	
	
	
	@RequestMapping(value="/{forumSlug}", method=RequestMethod.POST)
	public String postPostRegistrationForm(@PathVariable("forumSlug") String forumSlug, PostVO post, RedirectAttributes rttr) {
		
		log.info("PostController post post register form.............");
		
		post.setForumNumber(forumService.getForumByForumSlug(forumSlug).getNumber());
		postService.registerPost(post);
		
		rttr.addFlashAttribute("resultMessage", "새 글이 등록되었습니다.");
		
		StringBuilder redirectUri = new StringBuilder();
		redirectUri
			.append("redirect:/posts/")
			.append(forumSlug);
		
		return redirectUri.toString();
	}

	@RequestMapping(value="/{forumSlug}/{postNumber}", method=RequestMethod.PATCH)
	public String patchPost(@PathVariable("forumSlug") String forumSlug, PostVO post) {
		
		log.info("PostController patch post.............");
		
		postService.modifyPost(post);
		
		StringBuilder redirectUri = new StringBuilder();
		redirectUri
			.append("redirect:/posts/")
			.append(forumSlug)
			.append("/")
			.append(post.getNumber());
		
		return redirectUri.toString();
	}
	
	@RequestMapping(value="/{forumSlug}/{postNumber}", method=RequestMethod.DELETE)
	public String deletePost(@PathVariable("forumSlug") String forumSlug, @PathVariable("postNumber") Long postNumber, RedirectAttributes rttr) {
		
		log.info("PostController delete post.............");
		
		postService.deletePostByPostNumber(postNumber);
		
		
		StringBuilder redirectUri = new StringBuilder();
		redirectUri
			.append("redirect:/posts/")
			.append(forumSlug);
		
		return redirectUri.toString();
	}
}

 - 여기도 try catch 구문을 이용해서 에러가 발생하면 어떤 처리를 하도록 해야하는데, 어떤 처리를 해야되는지 감을 못 잡았다. REST API 관련 문서들 보면 3XX, 4XX 등에 대한 처리를 하던데, 이게 이 부분인가?

 

 

[ PostController Tests ]

@RunWith(SpringRunner.class)
@WebAppConfiguration
@ContextConfiguration({
	"file:src/main/webapp/WEB-INF/spring/root-context.xml",
	"file:src/main/webapp/WEB-INF/spring/security-context.xml",
	"file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml"})
@Log4j
public class PostControllerTests {

	@Setter(onMethod_ = @Autowired)
	private WebApplicationContext ctx;
	
	@Setter(onMethod_ = @Autowired)
	private PostService postService;
	
	private MockMvc mockMvc;
	
	
	@Before
	public void setup() {
		this.mockMvc = MockMvcBuilders.webAppContextSetup(ctx).build();
	}
	
	@Test
	public void testGetPostsByForumSlug() throws Exception {
		
		String forumSlug = "notice";
		
		URI uri = new URI("/posts/" + forumSlug);
		
		log.info(
				mockMvc.perform(MockMvcRequestBuilders.request("GET", uri))
				.andReturn()
				.getModelAndView()
				.getModelMap());
	}
	
	@Test
	public void testGetPostByPostNumber() throws Exception {
		
		String forumSlug = "notice";
		Long postNumber = 1L;
		
		URI uri = new URI("/posts/" + forumSlug + "/" + postNumber);
		
		log.info(
				mockMvc.perform(MockMvcRequestBuilders.request("GET", uri))
				.andReturn()
				.getModelAndView()
				.getModelMap());
	}
	
	@Test
	public void testGetPostRegistrationForm() throws Exception {
		
		String forumSlug = "notice";
		URI uri = new URI("/posts/" + forumSlug + "/registration");
		
		log.info(
				mockMvc.perform(MockMvcRequestBuilders.request("GET", uri))
				.andReturn()
				.getModelAndView()
				.getViewName());
	}
	
	@Test
	public void testPostPostRegistrationForm() throws Exception {
		
		String forumSlug = "notice";
		
		URI uri = new URI("/posts/" + forumSlug);
		
		log.info(
				mockMvc.perform(MockMvcRequestBuilders.request("POST", uri)
						.param("title", "mock test title")
						.param("content", "mock test content")
						.param("writer", "bibidi"))
				.andReturn()
				.getModelAndView()
				.getViewName());
	}
	
	@Test
	public void testPatchPost() throws Exception {
		
		String forumSlug = "notice";
		Long postNumber = 3L;
		
		URI uri = new URI("/posts/" + forumSlug + "/" + postNumber);
		
		PostVO postBeforePatch = postService.getPostByPostNumber(postNumber);
		
		log.info(
				mockMvc.perform(MockMvcRequestBuilders.request("PATCH", uri)
						.param("number", postNumber.toString())
						.param("title", "test patch post")
						.param("content", "patch post content"))
				.andReturn()
				.getModelAndView()
				.getViewName());
		
		PostVO postAfterPatch = postService.getPostByPostNumber(postNumber);
		
		log.info(postBeforePatch);
		log.info(postAfterPatch);
	}
	
	@Test
	public void testDeletePost() throws Exception {
		
		String forumSlug = "notice";
		Long postNumber = 5L;
		
		URI uri = new URI("/posts/" + forumSlug + "/" + postNumber);
		
		log.info(
				mockMvc.perform(MockMvcRequestBuilders.request("DELETE", uri))
				.andReturn()
				.getModelAndView()
				.getViewName());
	}
}

 -  다른 테스트와 다르게 WebAppConfiguration을 해줘야 한다. 또 MockMvc는 Setter를 이용해 주입하면 오류가 난다. 지금 생각해보니Dependency Injection에 대한 개념이 부족하다. 관련 자료를 찾아서 보충해야 한다.

 - 지금 다 작성하고 보니 모두 한 게시판에 대해 테스트를 한다. forumSlug를 상수로 선언하는 게 더 좋은가?

 

 

[ 화면 작성 ]

 - 부트스트랩 SB Admin2을 사용해서 만들어져 있는 컴포넌트를 이용할 땐 편하다. 그런데 내가 원하는 모양으로 만들려면 또 새로운 Div을 만들고 class를 지정하고 css를 만들어야하니 이거 또 자료를 찾아서 공부해야 되나 싶다.

 - 라이브러리 테이블 내에 thead, tbody 부분으로 나눠서 작성하던데 thead reference를 찾아보면 HTML5부터 지원되지 않는 속성들이 있고 하던데, 사용하는 것이 좋은지 안 좋은지 모르겠다. 의미 상으론 있는 게 나은 것 같은데.

 

리스트 페이지

 - 화면은 9 : 3으로 나눠서 9는 본문으로 사용하고 3은 광고를 넣거나 인기 게시물을 나열하도록 만들려고 남겨놨다. 본문은 크게 게시판 정보, 게시글로 나누고 게시글이 또 게시글 리스트, 버튼, 페이지네이션으로 구분된다.

 

 

조회 페이지
조회 페이지2

 - 조회 페이지이다. 게시글 정보를 나열하고 게시글 리스트를 나열하는데, 조회 중인 게시글에 해당하는 포스트를 '현재'로 나타내도록 만들었다. pagination처럼 active 클래스를 만들어서 시각적인 효과를 주면 더 좋을 것 같다.

 

 - 로그인 후 본인이 작성한 게시글에 들어왔을 때 보이는 화면이다. 글쓰기는 로그인을 한 사용자만 나오도록 되어있고 수정, 삭제는 본인이 작성한 게시글일 경우에만 나온다.

 - 아직 수정, 삭제 기능은 구현되어 있지 않다. form의 경우 지원하는 method가 get, post밖에 없다. patch, delete 요청을 보내려면 javascript로 작업해야 한다. 먼저 댓글 부분을 처리하고 나서 작업해야겠다. 

 - 좋아요, 싫어요도 댓글 부분 처리하고 작업.

 

 * Referecne

1. tcpschool.com/html-tags/thead : sdfsdf

 

 

[ JSTL Libraries ]

 - Core : https://docs.oracle.com/javaee/5/jstl/1.1/docs/tlddocs/c/tld-summary.html

 - Fmt : https://docs.oracle.com/javaee/5/jstl/1.1/docs/tlddocs/fmt/tld-summary.html

 

 

 

-------------------------------------------------------

 

21.06.01 update

 

[ Front - postService 작성 ]

console.log("Post Module .......");

const postService = (function() {
	
	const csrfHeaderName = document.querySelector("meta[name=csrfHeaderName]").getAttribute("content");
	const csrfToken = document.querySelector("meta[name=csrfTokenValue]").getAttribute("content");
	const fakeForumSlug = "temp";
	
	
	function addPost(post, callback, error) {
		
	}
	
	function getPost(postNumber, callback, error) {
		
	}
	
	function getPosts(param, callback, error) {
		
	}
	
	function updatePost(post, callback, error) {
		$.ajax({
			type : "PATCH",
			url : '/posts/' + fakeForumSlug + '/' + post.number,
			beforeSend : function(xhr) {
				xhr.setRequestHeader(csrfHeaderName, csrfToken);
			},
			data : JSON.stringify(post),
			contentType : 'application/json',
			success : function(data, status, xhr) {
				if (callback) {
					callback(data);
				}
			},
			error : function(xhr, status, errorThrown) {
				if (error) {
					error(errorThrown);
				}
			}
		});
	}
	
	function deletePost(postNumber, callback, error) {
		
		$.ajax({
			type : 'DELETE',
			url : '/posts/' + fakeForumSlug + '/' + postNumber,
			beforeSend : function(xhr) {
				xhr.setRequestHeader(csrfHeaderName, csrfToken);
			},
			success : function(data, status, xhr) {
				if (callback) {
					callback(data);
				}
			},
			error : function(xhr, status, errorThrown) {
				if (error) {
					error(errorThrown);
				}
			}
		});
	}
	
	return {
		addPost : addPost,
		getPost : getPost,
		getPosts : getPosts,
		updatePost : updatePost,
		deletePost : deletePost
	};
})();

 - JSTL로도 구현할 수 있지만 페이지 조작에 한계가 있어서 자바스크립트로 처리했다. 자바스크립트에도 http 통신은 있지만 사용하는 브라우저를 고려하는 등 구현 난이도가 높아 jquery ajax를 이용했다.

 

 

[ 게시물 삭제 이벤트 등록 ]

function registerBtnEvent() {
	const isLogin = userNickname == '' ? false : true;
				
	if (isLogin) {
                
		...
					
		// 게시물 삭제 이벤트 등록
		const postDeleteBtn = document.querySelector('.post-delete-link');
					
		if (postDeleteBtn !== null) {
			const result = location.pathname.split('/');
						
			postDeleteBtn.addEventListener('click', function(event) {
				event.preventDefault();
							
				postService.deletePost(
					postNumber,
					function(msg) {
						alert("msg");
						location.href = '/posts/' + forumSlug;
					}
				);
			});
		}
					
		...
                    
	}
}

 

 

[ 게시물 수정 이벤트 등록 ]

게시물 수정 화면

const urlTokens = location.pathname.split('/');
const forumSlug = urlTokens[2];
const postNumber = urlTokens[3];
const metaNickname = document.querySelector("meta[name='userNickname']");
const userNickname = !metaNickname ? "" : metaNickname.getAttribute("content");
		
registerBtnEvent();

function registerBtnEvent() {
	const isLogin = userNickname == '' ? false : true;
				
	if (isLogin) {
		const submitBtn = document.querySelector('#post-submit-btn');
					
		submitBtn.addEventListener('click', function() {
						
			const title = document.querySelector('#post-title').value;
			const content = document.querySelector('#post-content').value;
						
			post = {
				number : postNumber,
				title : title,
				content : content
			};
						
			postService.updatePost(
				post,
				function(msg) {
					alert(msg);
					location.href = '/posts/' + forumSlug + '/' + postNumber;
			});
		});
	}
}

 - cookie, session에 대한 개념이 부족해서 head의 meta에 userNickname을 만든 뒤 그걸 자바스크립트를 이용해 읽어와 처리하도록 작성했다. 그리고 nickname이 아니라 id를 이용해 구현하는 것이 좀 더 일반적인 구현인데, 처음 설계를 실수해서 지금 고치기엔 시간이 조금 많이 걸린다 ㅎㅎ; 처음에 이거 만들 즈음엔 프런트 쪽에서 어떻게 데이터 처리를 하는지 몰라서 사용자 관점에서 작성하자고 결정했고, 사용자가 볼 때 서로를 구별하는 기준이 userNickname이니 이걸 이용해서 데이터를 처리하자는 식으로 생각했는데, 지금 보니 좀 그렇다.

 

 

 

]

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

'(구)게시판 프로젝트' 카테고리의 다른 글

댓글, 대댓글  (1) 2021.05.11
권한 관련 작업  (0) 2021.05.05
(멀티)게시판  (0) 2021.05.04
이름 짓는 법 총 정리  (1) 2021.04.28
메인 화면  (0) 2021.04.27
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함