Spring Framework-11

유호준·2021년 3월 26일
0

Spring Framework

목록 보기
12/21

🔗이제 글과 유저를 연결해보자!


DB Table 수정

다음 SQL을 수행하여서 외래키를 추가해 user 테이블과 post 테이블을 연결해줍니다.

alter table post drop name;
alter table post add user_id int;
alter table post add foreign key(user_id) references user(id);

PostVO 수정

name 필드를 지우고 다음과 같이 수정합니다. user는 작성한 사람의 정보가 담길 필드입니다.

@Data
public class PostVO {
    private int id;
    private String title;
    private String content;
    private Timestamp created_date = new Timestamp(new Date().getTime());
    private UserVO user;
}

View 수정

board.jsp 수정

원래 name 필드를 출력하는 부분을 다음과 같이 수정합니다.

<tbody>
	<c:forEach items="${postList}" var="post">
		<tr>
			<td>${post.id}</td>
			<td><a href="/post/${post.id}">${post.title}</a></td>
			<td>${post.user.name}</td>
			<td><fmt:formatDate value="${post.created_date}" pattern="yyyy-MM-dd"/></td>
		</tr>
	</c:forEach>
</tbody>

post.jsp 수정

마찬가지로 name 필드를 출력하는 부분을 다음과 같이 수정합니다. 또한 모델 post가 없을 때, 글을 등록하는 부분에서 name을 입력하는 부분을 지웁니다. 그리고 수정할 때 input전체의 readonly 속성을 제거하는 것에서 nametitle인 태그의 readonly속성을 지우는 것으로 수정하고, ajaxname의 값을 받아 전송하는 부분을 지웁니다.

<div class="form-group">
	<input type="text" class="form-control form-control-user" name="name" placeholder="name" value="${post.user.name}" readonly>
</div>
<c:otherwise>
	<form action="/post" method="post" class="user">
		<div class="form-group">
			<input type="text" class="form-control form-control-user" name="title" placeholder="Title">
		</div>
		<div class="form-group">
			<textarea class="form-control form-control-user" name="content"></textarea>
		</div>
		<button type="submit" class="btn btn-primary btn-user btn-block">
                                        Register Post
		</button>
	</form>
</c:otherwise>
<c:if test="${isModify}">
    <script>
        $("[name='title']").removeAttr("readonly")
        $("textarea").removeAttr("readonly")
        $("#modifySubmit").click(function (){
            var postVO =new  Object()
            postVO.id = $("[name='id']").val()
            postVO.title = $("[name='title']").val()
            postVO.content= $("[name='content']").val()

            $.ajax({
                type:"PUT",
                url:"/post",
                contentType:"application/json; charset=utf-8",
                data:JSON.stringify(postVO),
                success:function (data) {
                    if(data)
                        location.href="/post/"+postVO.id
                }
            })
        })
    </script>
</c:if>

PostMapper.xml 수정

PostMapper.xml을 다음과 같이 수정합니다. SELECTpost를 받아오는 부분을 JOIN을 사용해서 user의 정보도 같이 받아오도록 수정합니다. 또한 INSERT할 때 user_iduserid로 저장할 수 있도록 합니다. 마지막으로 UPDATE에서 name을 저장하는 부분을 지웁니다.

<mapper namespace="ac.kr.smu.mapper.PostMapper">

    <resultMap id="post" type="PostVO">
        <id property="id" column="id" />
        <id property="title" column="title" />
        <id property="content" column="content" />
        <id property="created_date" column="created_date" />
        <association property="user"  javaType="UserVO" >
            <result property="id"  column="user_id" />
            <result property="email"  column="email" />
            <result property="name"  column="name" />
        </association>
    </resultMap>

    <insert id="save">
        INSERT INTO post(title,content,created_date,user_id)
        VALUES(#{title},#{content},#{created_date},#{user.id})
    </insert>
    <select id="findAll" resultType="PostVO" resultMap="post">
        SELECT * from post as p JOIN user AS u on p.user_id = u.id
    </select>
    <select id="findById" resultType="PostVO" resultMap="post">
        SELECT * FROM post as p JOIN user AS u ON p.user_id = u.id WHERE p.id=#{id};
    </select>
    <select id="update" resultType="PostVO">
        UPDATE post SET title=#{title}, content=#{content} WHERE id=#{id};
        SELECT * FROM post as p JOIN user AS u ON p.user_id = u.id WHERE p.id=#{id};
    </select>
    <delete id="delete">
        DELETE FROM post WHERE id=#{id}
    </delete>
</mapper>

resultMap태그는 PostVO로 객체가 만들어질때 매핑되는 columnproperty를 작성하는 태그입니다. 그 안에 association태그는 UserVO로 묶어서 user 필드로 매핑하는 것을 설정하는 부분입니다.


UserService 수정

email로 유저의 정보를 받아올 수 있도록 수정합니다.

public interface UserService {
    public void save(UserVO userVO);
    public boolean checkEmailDuplication(String email);
    public boolean checkPassword(String email, String password);
    public UserVO findByEmail(String email);
}
@RequiredArgsConstructor
@Service
public class UserServiceImpl implements UserService {
    private final UserMapper userMapper;

    @Override
    public void save(UserVO userVO) {
        userMapper.save(userVO);
    }

    @Override
    public boolean checkEmailDuplication(String email) {
        return userMapper.checkEmailDuplication(email)==0;
    }

    @Override
    public boolean checkPassword(String email, String password) {
        return password.equals(userMapper.findByEmail(email).getPassword());
    }

    @Override
    public UserVO findByEmail(String email) {
        return userMapper.findByEmail(email);
    }
}

UserArgumentResolver 추가

이제 우리는 글을 생성할 때 postVO유저의 정보를 저장해 주어야합니다. 따라서 Controller에 파라미터를 가공하거나 추가해주는 ArgumentResolver를 추가해줄 것입니다.

public class UserArgumentResolver implements HandlerMethodArgumentResolver {

    private UserService userService;
	/*
		어떤 파라미터가 들어올 때 ArgumentResolver가 수행할지
	*/
    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        return methodParameter.getParameterType().equals(UserVO.class);
    }
	/*
		세션에서 email을 가져와 UserService를 이용하여 User반환
	*/
    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
	/*
		HttpServletRequest에서 세션 받아오기
		RequestContextHolder가 현재 요청의 내용을 가지고 있는 클래스인데,
		여기서 currentRequestAttributes() 메소드를 호출하여 현재 요청의 속성을 받아오고, 
		이것을 ServletRequestAttribuest로 형변환하여 getRequest() 메소드를 호출하면,
		HttpServletRequest를 받아올 수 있다.
	*/
        HttpSession session = ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest().getSession();
        /*
        * 우선순위 때문에 의존성 주입이 되지 않아서 직접 설정에서 빈을 꺼내서 초기화
        * */
        if(userService==null){
            WebApplicationContext context =
                    WebApplicationContextUtils.getWebApplicationContext(session.getServletContext());
            userService = context.getBean(UserService.class);
        }

        return userService.findByEmail((String)session.getAttribute("userSession"));
    }



}

ServletConfig 수정

ServletConfig 클래스에서 아래 메소드를 추가하여 UserArgumentResolver를 추가해줍니다.

@Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        WebMvcConfigurer.super.addArgumentResolvers(resolvers);
        resolvers.add(new UserArgumentResolver());
    }

PostController 수정

글을 생성할 때 유저의 정보를 저장할 수 있도록 userVO를 넣어서 저장시킵니다.userVO는 위에서 설명했다싶이 UserArgumentResolver가 세션에 저장되어 있는 email로 찾아서 넣어줍니다.

@PostMapping
public String postPost(PostVO postVO, UserVO userVO) {
        postVO.setUser(userVO);
        postService.save(postVO);
        return "board";
}

userService를 필드에 추가하고 의존성 주입을 받을 수 있도록 합니다.


테스트

편의를 위해 기존의 글을 모두 지우고 나서 합니다.

delete from post





이를 응용해 여러가지를 할 수 있습니다. 예를 들자면 댓글과 대댓글을 묶어서 한번에 반환할 수 있습니다. 하지만 이를 남용하면 JOIN이 많아져 연산시간이 길어집니다.

0개의 댓글