mirror of https://github.com/halo-dev/halo
feat: support photo likes (#1537)
* feat: support photo likes * feat: add CacheLock annotation to likes apipull/1541/head
parent
e1737145ac
commit
c149d53f7e
|
@ -18,6 +18,8 @@ import org.springframework.web.bind.annotation.PutMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import run.halo.app.cache.lock.CacheLock;
|
||||||
|
import run.halo.app.cache.lock.CacheParam;
|
||||||
import run.halo.app.model.dto.PhotoDTO;
|
import run.halo.app.model.dto.PhotoDTO;
|
||||||
import run.halo.app.model.entity.Photo;
|
import run.halo.app.model.entity.Photo;
|
||||||
import run.halo.app.model.params.PhotoParam;
|
import run.halo.app.model.params.PhotoParam;
|
||||||
|
@ -87,6 +89,13 @@ public class PhotoController {
|
||||||
return new PhotoDTO().convertFrom(photoService.update(photo));
|
return new PhotoDTO().convertFrom(photoService.update(photo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PutMapping("{photoId:\\d+}/likes")
|
||||||
|
@ApiOperation("Likes a photo")
|
||||||
|
@CacheLock(autoDelete = false, traceRequest = true)
|
||||||
|
public void likes(@PathVariable @CacheParam Integer photoId) {
|
||||||
|
photoService.increaseLike(photoId);
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("teams")
|
@GetMapping("teams")
|
||||||
@ApiOperation("Lists all of photo teams")
|
@ApiOperation("Lists all of photo teams")
|
||||||
public List<String> listTeams() {
|
public List<String> listTeams() {
|
||||||
|
|
|
@ -6,7 +6,10 @@ import run.halo.app.model.dto.base.OutputConverter;
|
||||||
import run.halo.app.model.entity.Photo;
|
import run.halo.app.model.entity.Photo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Photo dto.
|
||||||
|
*
|
||||||
* @author ryanwang
|
* @author ryanwang
|
||||||
|
* @author guqing
|
||||||
* @date 2019-03-21
|
* @date 2019-03-21
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
|
@ -27,4 +30,6 @@ public class PhotoDTO implements OutputConverter<PhotoDTO, Photo> {
|
||||||
private String location;
|
private String location;
|
||||||
|
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
|
private Long likes;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import javax.persistence.TemporalType;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
import org.hibernate.annotations.ColumnDefault;
|
||||||
import org.hibernate.annotations.GenericGenerator;
|
import org.hibernate.annotations.GenericGenerator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,6 +80,13 @@ public class Photo extends BaseEntity {
|
||||||
@Column(name = "team")
|
@Column(name = "team")
|
||||||
private String team;
|
private String team;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Likes.
|
||||||
|
*/
|
||||||
|
@Column(name = "likes", nullable = false)
|
||||||
|
@ColumnDefault("0")
|
||||||
|
private Long likes;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void prePersist() {
|
public void prePersist() {
|
||||||
super.prePersist();
|
super.prePersist();
|
||||||
|
@ -102,5 +110,9 @@ public class Photo extends BaseEntity {
|
||||||
if (team == null) {
|
if (team == null) {
|
||||||
team = "";
|
team = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (likes == null || likes < 0) {
|
||||||
|
likes = 0L;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package run.halo.app.repository;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.data.jpa.repository.Modifying;
|
||||||
import org.springframework.data.jpa.repository.Query;
|
import org.springframework.data.jpa.repository.Query;
|
||||||
import run.halo.app.model.entity.Photo;
|
import run.halo.app.model.entity.Photo;
|
||||||
import run.halo.app.repository.base.BaseRepository;
|
import run.halo.app.repository.base.BaseRepository;
|
||||||
|
@ -12,6 +13,7 @@ import run.halo.app.repository.base.BaseRepository;
|
||||||
*
|
*
|
||||||
* @author johnniang
|
* @author johnniang
|
||||||
* @author ryanwang
|
* @author ryanwang
|
||||||
|
* @author guqing
|
||||||
* @date 2019-04-03
|
* @date 2019-04-03
|
||||||
*/
|
*/
|
||||||
public interface PhotoRepository
|
public interface PhotoRepository
|
||||||
|
@ -33,4 +35,15 @@ public interface PhotoRepository
|
||||||
*/
|
*/
|
||||||
@Query(value = "select distinct p.team from Photo p")
|
@Query(value = "select distinct p.team from Photo p")
|
||||||
List<String> findAllTeams();
|
List<String> findAllTeams();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates photo likes.
|
||||||
|
*
|
||||||
|
* @param likes likes delta
|
||||||
|
* @param photoId photo id must not be null
|
||||||
|
* @return updated rows
|
||||||
|
*/
|
||||||
|
@Modifying
|
||||||
|
@Query("update Photo p set p.likes = p.likes + :likes where p.id = :photoId")
|
||||||
|
int updateLikes(long likes, Integer photoId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,4 +79,11 @@ public interface PhotoService extends CrudService<Photo, Integer> {
|
||||||
* @return list of teams
|
* @return list of teams
|
||||||
*/
|
*/
|
||||||
List<String> listAllTeams();
|
List<String> listAllTeams();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increases photo likes(1).
|
||||||
|
*
|
||||||
|
* @param photoId photo id must not be null
|
||||||
|
*/
|
||||||
|
void increaseLike(Integer photoId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.persistence.criteria.Predicate;
|
import javax.persistence.criteria.Predicate;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
|
@ -13,7 +14,9 @@ import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.data.jpa.domain.Specification;
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import run.halo.app.exception.BadRequestException;
|
||||||
import run.halo.app.model.dto.PhotoDTO;
|
import run.halo.app.model.dto.PhotoDTO;
|
||||||
import run.halo.app.model.entity.Photo;
|
import run.halo.app.model.entity.Photo;
|
||||||
import run.halo.app.model.params.PhotoParam;
|
import run.halo.app.model.params.PhotoParam;
|
||||||
|
@ -25,11 +28,13 @@ import run.halo.app.service.base.AbstractCrudService;
|
||||||
import run.halo.app.utils.ServiceUtils;
|
import run.halo.app.utils.ServiceUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PhotoService implementation class
|
* PhotoService implementation class.
|
||||||
*
|
*
|
||||||
* @author ryanwang
|
* @author ryanwang
|
||||||
|
* @author guqing
|
||||||
* @date 2019-03-14
|
* @date 2019-03-14
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class PhotoServiceImpl extends AbstractCrudService<Photo, Integer> implements PhotoService {
|
public class PhotoServiceImpl extends AbstractCrudService<Photo, Integer> implements PhotoService {
|
||||||
|
|
||||||
|
@ -116,6 +121,20 @@ public class PhotoServiceImpl extends AbstractCrudService<Photo, Integer> implem
|
||||||
return photoRepository.findAllTeams();
|
return photoRepository.findAllTeams();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void increaseLike(Integer photoId) {
|
||||||
|
Assert.notNull(photoId, "Photo id must not be null");
|
||||||
|
|
||||||
|
int affectedRows = photoRepository.updateLikes(1L, photoId);
|
||||||
|
|
||||||
|
if (affectedRows != 1) {
|
||||||
|
log.error("Photo with id: [{}] may not be found", photoId);
|
||||||
|
throw new BadRequestException(
|
||||||
|
"Failed to increase likes 1 for photo with id " + photoId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private Specification<Photo> buildSpecByQuery(@NonNull PhotoQuery photoQuery) {
|
private Specification<Photo> buildSpecByQuery(@NonNull PhotoQuery photoQuery) {
|
||||||
Assert.notNull(photoQuery, "Photo query must not be null");
|
Assert.notNull(photoQuery, "Photo query must not be null");
|
||||||
|
|
Loading…
Reference in New Issue