좋아요 기능
게시글에 좋아요 버튼 처음 누르면 좋아요,
이미 좋아요를 누른 게시글에 또 좋아요를 누르면 좋아요 취소가 되는 기능 구현.
좋아요를 누르는 파트1과,
좋아요를 누른 게시글을 조회2할 수 있는 두 파트로 나눠 정리한다.
[좋아요]
1) likes 테이블 생성.
create table likes (
member_idx int,
product_idx int,
foreign key (member_idx) references member (idx),
foreign key (product_idx) references product (idx),
primary key (member_idx, product_idx)
);
* 이전글 [Spring Boot + JWT + Security + Security 권한 설정해서 '회원가입/로그인 구현'] 참고
- member_idx:
기존 사용자 table인 member table의 idx(pk)
- product_idx:
기존 상품 테이블인 product table의 idx(pk)
2) ProductController
@ResponseBody
@GetMapping("/like/{idx}")
public String likeProduct(@AuthenticationPrincipal UserLoginRes userLoginRes, @PathVariable int idx) {
return productService.likeProduct(userLoginRes.getIdx(),idx);
}
3) ProductService
public String likeProduct(int userLoginResIdx, int idx){
return productDao.likeProduct(userLoginResIdx, idx);
}
4) ProductDao
public String likeProduct(int userLoginResIdx, int idx) {
String getLikeQuery = "select * from likes where member_idx=? and product_idx=?";
List<Map<String, Object>> rows = this.jdbcTemplate.queryForList(getLikeQuery, userLoginResIdx, idx);
해당 사용자가
게시글에 좋아요를 누른 적이 있는지 확인한다.
member_idx와 product_idx를 뽑아 rows에 저장해서
rows의 길이가 0인 경우, 즉 좋아요 누른 게시글이 없는 경우
like 테이블에 member_idx와 product_idx를 저장하자.
if (rows.size() == 0) {
String createProductQuery = "insert into likes (member_idx, product_idx) VALUES (?, ?)";
Object[] createProductParams = new Object[]{userLoginResIdx, idx};
this.jdbcTemplate.update(createProductQuery, createProductParams);
String getLastInsertIdxQuery = "select last_insert_id()";
int lastInsertIdx = this.jdbcTemplate.queryForObject(getLastInsertIdxQuery, int.class);
return "added";
}
그럼 그 반대의 경우는
rows의 길이가 0이 아닌, 이미 좋아요를 누른 게시글이다.
DELETE 쿼리로 좋아요 취소를 구현한다.
else {
String createProductQuery = "DELETE FROM likes WHERE member_idx=? and product_idx=?";
Object[] createProductParams = new Object[]{userLoginResIdx, idx};
this.jdbcTemplate.update(createProductQuery, createProductParams);
String getLastInsertIdxQuery = "select last_insert_id()";
int lastInsertIdx = this.jdbcTemplate.queryForObject(getLastInsertIdxQuery, int.class);
return "deleted";
}
[좋아요 누른 게시글 조회]
GetProductWithImageAndLikesRes 라는 모델을 생성한다.
기존의 GetProductWithImageRes 에서 like_check(Boolean) 변수만 하나 추가됐다.
@Getter
@Setter
@AllArgsConstructor
public class GetProductWithImageAndLikesRes {
private int idx;
private String name;
private int brandIdx;
private int categoryIdx;
private int price;
private int salePrice;
private String deliveryType;
private String isTodayDeal;
private String filename;
private Boolean like_check;
}
ProductDao
getProductsWithProductImage 메서드에서 로그인 하지 않은 사용자들은
like_check 가 false가 되게 한다.
public List<GetProductWithImageAndLikesRes> getProductsWithProductImage() {
String getProductsQuery = "SELECT * FROM product left JOIN (SELECT productIdx, group_concat(filename) FROM productImage group by productIdx) as pi ON product.idx=pi.productIdx";
return this.jdbcTemplate.query(getProductsQuery,
(rs, rowNum) -> new GetProductWithImageAndLikesRes(
rs.getObject("idx", int.class),
rs.getString("name"),
rs.getObject("brandIdx", int.class),
rs.getObject("categoryIdx", int.class),
rs.getObject("price", int.class),
rs.getObject("salePrice", int.class),
rs.getString("deliveryType"),
rs.getString("isTodayDeal"),
rs.getString("filename"),
false
));
}
getProductsWithProductImageAndLikes 메서드에서 로그인한 사용자는
like_check 가 rs.getBoolean("like_ckeck") 즉 true나 false가 된다.
public List<GetProductWithImageAndLikesRes> getProductsWithProductImageAndLikes(int member_idx) {
String getProductsQuery = "SELECT *, ifnull(product_idx, false) as like_ckeck FROM product left JOIN (SELECT productIdx, group_concat(filename) as filename FROM productImage group by productIdx) as pi ON product.idx=pi.productIdx LEFT JOIN (SELECT product_idx FROM likes WHERE member_idx=?) as likes ON likes.product_idx=product.idx;";
return this.jdbcTemplate.query(getProductsQuery,
(rs, rowNum) -> new GetProductWithImageAndLikesRes(
rs.getObject("idx", int.class),
rs.getString("name"),
rs.getObject("brandIdx", int.class),
rs.getObject("categoryIdx", int.class),
rs.getObject("price", int.class),
rs.getObject("salePrice", int.class),
rs.getString("deliveryType"),
rs.getString("isTodayDeal"),
rs.getString("filename"),
rs.getBoolean("like_ckeck")
),member_idx);
}
Advanced REST client로 테스트.
1)
1)
좋아요가 없을 때, 좋아요 눌러서 added 출력.
좋아요 누른 상태에서, 좋아요 눌러서 deleted 출력.
2) 조회 테스트
GET, http://localhost:8080/product/lists
* jdbcTemplate getObject null 일 때 처리 참고:
Checking for a null int value from a Java ResultSet
* MySQL 컬럼 순서 바꿔 출력하기, 컬럼 별명 붙이기
컬럼 이름에 number나 sales만 표시하면 어떤 데이터를 표시한 것인지 잘 모를 수 있다..
select 컬럼명 as 별명 from 테이블명;
이런 경우 컬럼을 알기 쉽도록 별명을 붙일 수 있는데,
컬럼 number에는 사원번호, sales 에는 매출이라는 별명을 붙여 보자.
select number as 사원번호, sales as 매출 from table_sales;
'🍃 𝗦𝗽𝗿𝗶𝗻𝗴 𝗕𝗼𝗼𝘁' 카테고리의 다른 글
스프링부트x리액트 '카카오 로그인 하기(소셜 로그인 )' 카카오API+JWT+OAuth2 [1] (3) | 2022.04.26 |
---|---|
[Springboot] 컨트롤러에서 Json 데이터 받을 때 오류 out of START_ARRAY token..Cannot deserialize value of type JsonToken.. (0) | 2022.04.06 |
스프링부트 JWT 인증 과정 (0) | 2022.03.18 |
JWT(Json Web Token) :: JWT 형식, 동작과정 (0) | 2022.03.18 |
Spring Boot + JWT + Security + Security 권한 설정해서 '회원가입/로그인 구현' (0) | 2022.03.18 |
댓글