안녕하세요! 보라입니다💜
벌써 8주차라니! 두 달이 정말 빠르게 지나갔던 것 같습니다.
저도 이제 바쁜 일들이 거의 끝나서, 공부에만 집중할 수 있게 되었답니다~!
코로나로 인해 잠시 쉬었던 운동도 다시 다니고 있고, 알바를 그만 두니 주말에 여유 시간이 생겨 너무 좋습니다😊
당장 급한 일을 처리하느라 살짜쿵 미뤄 놓았던 강의들만 조금.. 남은 상태입니다 호호
이번 주말을 활용하여 하긴 했지만, 꼼꼼히 하지 못 했던! 공부들을 해보려고 합니다😙
이번 주차 워크북 시작합니당!
- 실습 과정
- 트러블 슈팅
- 강의 후기
유저의 피드를 생각해보자.
나의 피드인지, 다른 사람의 피드인지에 따라 구성이 다르므로 구별하는 변수를 만들어준다.
또 피드에는 유저의 정보와 유저의 게시글들이 있는데, 다소 복잡하기 때문에 각각 객체 정보로 만들어주었다.
이때, 한 명의 유저는 여러 개의 게시글을 작성했을 수 있으므로 List로 만들어준다!
@Getter
@Setter
@AllArgsConstructor
public class GetUserFeedRes {
private boolean _isMyFeed; //내 피드인지 다른 사람의 피드인지 구별 하는 변수
private GetUserInfoRes getUserInfo;
private List<GetUserPostsRes> getUserPosts;
}
피드를 나타내기 위한 유저 정보에는 무엇이 필요할까?
아래와 같이 만들어주었다.
@Getter
@Setter
@AllArgsConstructor
public class GetUserInfoRes {
private String nickName;
private String name;
private String profileImgUrl;
private String website;
private String introduce;
private int followerCount;
private int followingCount;
private int postCount;
}
마지막으로 유저가 작성한 게시글 정보이다. 게시글의 번호와 이미지가 필요하다.
public class GetUserPostsRes {
private int postIdx;
private String postImgUrl;
}
//유저 피드 조회
@ResponseBody
@GetMapping("/{userIdx}") // (GET) 127.0.0.1:9000/users
public BaseResponse<GetUserFeedRes> getUserFeed(@PathVariable("userIdx") int userIdx) {
try{
GetUserFeedRes getUserFeedRes = userProvider.retrieveUserFeed(userIdx, userIdx);
return new BaseResponse<>(getUserFeedRes);
} catch(BaseException exception){
return new BaseResponse<>((exception.getStatus()));
}
}
public GetUserInfoRes selectUserInfo(int userIdx){
String selectUserInfoQuery = "SELECT u.userIdx as userIdx," +
" u.nickName as nickName, " +
" u.name as name, " +
" u.profileImgUrl as profileImgUrl, " +
" u.website as website, " +
" u.introduce as introduce,\n" +
" IF(postCount is null, 0, postCount) as postCount,\n" +
" IF(followerCount is null, 0, followerCount) as followCount,\n" +
" IF(followingCount is null, 0, followingCount) as followingCount\n" +
"FROM User as u\n" +
" left join (SELECT userIdx, COUNT(postIdx) as postCount\n" +
" FROM Post\n" +
" WHERE status = 'ACTIVE'\n" +
" GROUP BY userIdx) p on p.userIdx = u.userIdx\n" +
" left join (SELECT followerIdx, COUNT(followIdx) as followerCount\n" +
" FROM Follow\n" +
" WHERE status = 'ACTIVE'\n" +
" GROUP BY followerIdx) f1 on f1.followerIdx = u.userIdx\n" +
" left join (SELECT followeeIdx, COUNT(followIdx) as followingCount\n" +
" FROM Follow\n" +
" WHERE status = 'ACTIVE'\n" +
" GROUP BY followeeIdx) f2 on f2.followeeIdx = u.userIdx\n" +
"\n" +
"WHERE u.userIdx = ? and u.status = 'ACTIVE';";
int selectUserInfoParam=userIdx;
return this.jdbcTemplate.queryForObject(selectUserInfoQuery,
(rs,rowNum) -> new GetUserInfoRes(
rs.getString("nickName"),
rs.getString("name"),
rs.getString("profileImgUrl"),
rs.getString("website"),
rs.getString("introduce"),
rs.getInt("followerCount"),
rs.getInt("followingCount"),
rs.getInt("postCount")
),selectUserInfoParam);
}
그리고! 유저의 게시물 리스트를 받아오는 함수
public List<GetUserPostsRes> selectUserPosts(int userIdx){
String selectUserPostsQuery =
"SELECT p.postIdx as postIdx,\n" +
" pi.imgUrl as postImgUrl\n" +
"FROM Post as p\n" +
" join User as u on u.userIdx = p.userIdx\n" +
" join PostImgUrl as pi on pi.postIdx = p.postIdx and pi.status = 'ACTIVE'\n" +
"WHERE p.status = 'ACTIVE' AND u.userIdx = ?\n" +
"GROUP BY p.postIdx\n" +
"ORDER BY p.createdAt desc;";
int selectUserPostsParam=userIdx;
return this.jdbcTemplate.query(selectUserPostsQuery,
(rs,rowNum) -> new GetUserPostsRes(
rs.getInt("postIdx"),
rs.getString("postImgUrl")
),selectUserPostsParam);
}
작성하다보니, 유저 id가 정말 존재하는지 확인하는 validation이 필요하다!
그래서 UserDao에는 이렇게
UserProvider에는 이렇게 만들어주었다.
//에러 발생
게시물 리스트 조회 API를 만들기 위해서는 src 아래 경로에 post라는 새로운 패키지를 만들어줘야한다.
그래서 아래와 같이 만들어주었고, Post를 위한 Controller, Dao, Provider, Service도 만들어주었다. User의 코드를 참고했다!
//GetPostImgRes 파일
@Getter
@Setter
@AllArgsConstructor
public class GetPostImgRes {
private int postImgIdx;
private String imgUrl;
}
//GetPostsRes 파일
@Getter
@Setter
@AllArgsConstructor
public class GetPostsRes {
private int postIdx;
private int userIdx;
private String nickName;
private String profileImgUrl;
private String content;
private int postLikeCount;
private int commentCount;
private String updateAt;
private String likeOrNot;
private List<GetPostImgRes> imgs;
}
//PostController 파일 안에 작성
@ResponseBody
@GetMapping("") // 쿼리스트링
public BaseResponse<List<GetPostsRes>> getPosts(@RequestParam int userIdx) {
try{
List<GetPostsRes> getPostsRes = postProvider.retrievePosts(userIdx);
return new BaseResponse<>(getPostsRes);
} catch(BaseException exception){
return new BaseResponse<>((exception.getStatus()));
}
}
//PostProvider 파일 안에 작성
public List<GetPostsRes> retrievePosts(int userIdx) throws BaseException {
Boolean isMyFeed = true;
if(checkUserExist(userIdx) == 0) {
throw new BaseException(USERS_EMPTY_USER_ID);
}
try{
List<GetPostsRes> getPosts = postDao.selectPosts(userIdx);
return getPosts;
}
catch (Exception exception) {
throw new BaseException(DATABASE_ERROR);
}
}
//userid가 존재하는지 체크하는 함수
public int checkUserExist(int userIdx) throws BaseException{
try{
return postDao.checkUserExist(userIdx);
} catch (Exception exception){
throw new BaseException(DATABASE_ERROR);
}
}
//피드를 보여주는 화면에서 필요한 데이터들을 받아와주는 함수
public List<GetPostsRes> selectPosts(int userIdx){
String selectPostsQuery =
"SELECT p.postIdx as postIdx,\n" +
" u.userIdx as userIdx,\n" +
" u.nickName as nickName,\n" +
" u.profileImgUrl as profileImgUrl,\n" +
" p.content as content,\n" +
" IF(postLikeCount is null, 0, postLikeCount) as postLikeCount,\n" +
" IF(commnentCount is null, 0, commentCount) as commmentCount,\n" +
" CASE WHEN timestampdiff(second, p.updatedAt, current_timestamp) < 60\n" +
" THEN concat(timestampdiff(second, p.updatedAt, current_timestamp), '초 전')\n" +
" WHEN timestampdiff(minute, p.updatedAt, current_timestamp) < 60\n" +
" THEN concat(timestampdiff(minute, p.updatedAt, current_timestamp), '분 전')\n" +
" WHEN timestampdiff(hour, p.updatedAt, current_timestamp) < 24\n" +
" THEN concat(timestampdiff(hour, p.updatedAt, current_timestamp), '시간 전')\n" +
" WHEN timestampdiff(day, p.updatedAt, current_timestamp) < 365\n" +
" THEN concat(timestampdiff(day, p.updatedAt, current_timestamp), '일 전')\n" +
" ELSE timestampdiff(year, p.updatedAt, current_timestamp)\n" +
" END AS updatedAt,\n" +
" IF(pl.status = 'ACTIVE', 'Y', 'N') as likeOrNot\n" +
" FROM Post as p\n" +
" JOIN User as u on u.userIdx = p.useridx\n" +
" LEFT JOIN (SELECT postIdx, userIdx, count(postLikeidx) as postLikeCount\n" +
" FROM PostLike\n" +
" WHERE status ='ACTIVE'\n" +
" GROUP BY postIdx) as pl on p.postIdx = pl.postIdx\n" +
" LEFT JOIN (SELECT postIdx, COUNT(commentIdx) as commentCount\n" +
" FROM Comment\n" +
" WHERE status='ACTIVE') as c on c.postIdx = p.postIdx\n" +
" WHERE p.status = 'ACTIVE' and p.postIdx = ?";
int selectPostsParam=userIdx;
return this.jdbcTemplate.query(selectPostsQuery,
(rs,rowNum) -> new GetPostsRes(
rs.getInt("postIdx"),
rs.getInt("userIdx"),
rs.getString("nickname"),
rs.getString("profileImgUrl"),
rs.getString("content"),
rs.getInt("postLikeCount"),
rs.getInt("commentCount"),
rs.getString("updatedAt"),
rs.getString("likeOrNOt"),
getPostImgRes=this.jdbcTemplate.query("\"SELECT pi.postImgUrlIdx, pi.imgUrl +\n" +
" \" FROM PostImgUrl as pi\" +\n" +
" \" JOIN Post as p on p.postIdx = pi.postIdx +\n" +
" \" WHERE pi.status = 'ACTIVE' and p.postIdx = ?;\"",
(rk,rownum) -> new GetPostImgRes(
rk.getInt("postImgUrlIdx"),
rk.getString("imgUrl")
), rs.getInt("postIdx")
)
),selectPostsParam);
}
//userid가 존재하는지 체크하는 함수
public int checkUserExist(int userIdx){
String checkUserExistQuery = "select exists(select userIdx from User where userIdx = ?)";
int checkUserExistParams = userIdx;
return this.jdbcTemplate.queryForObject(checkUserExistQuery,
int.class,
checkUserExistParams);
}
Postman에서 테스트를 하려고 했는데 오류가 발생했다.
Database 에러라는 것을 보아, Provider 쪽 에러 같았다.
이번 강의는 본격적으로 코딩이 포함되어 있었던 것 같다! 사실 백엔드 개발자로 진로를 정하게 된 계기가 2학년 때 인터넷 프로그래밍 과목에서 웹 프로젝트를 했었던 것인데, 이번 주차 실습을 하면서 그때 생각이 났다 ㅎㅎ
인프 과목을 듣고 웹 개발에 흥미가 생겨서 프로젝트도 해보고 이것저것 해봤었던 게 기억이 난다. 그때는 그저 교수님이 가르쳐주시는 대로 따라하기만 했고, 따라하더라도 시간이 부족해서 Controller, Dao, Provider, Service 등을 왜 만드는지, 함수가 어떻게 동작하는지도 이해하지 못 했었다. 이제는 본격적으로, 나에게 맞는 분야를 찾아 자발적으로 공부를 해야하는 3학년이 되었고 지금 다시 접했을 땐 그때보다 수월하게 이해할 수 있었다.
그래도 아직은 조금 이해가 안되는 부분이 있긴 하다. 이번 주말에 시간이 널널하니 README 파일도 다시 한 번 읽어보면서 제대로 포스팅하게 될 것 같다!
그리고 실습하면서 느낀 건데, 인텔리제이 버그 너무 많고 진짜 구린 것 같다 ㅎㅎ😊😍 (근데 이클립스는 더 구림ㅋㅋ) 솔직히 내가 실수해서 오류 뜬 걸 인텔리제이 버그라고 생각해서 화난 적도 있긴 한데 인텔리제이 버그 뜰 때마다 진짜 화면 뿌시고 싶었다 ㅎㅎ😋✨(대충 그지같은 말을 예쁘게 쓰면 예쁜 말이 된다고 믿는 사람) 근데 이건 인텔리제이 입장도 들어봐야 될 듯 합니다 ㅋ
8주차가 되기까지 쉽게 온 것 같진 않지만, 제가 관심있는 분야를 공부할 수 있는 기회를 얻어서 행운이라고 생각합니다!! 다음주도 파이팅~