7 Commits

19 changed files with 624 additions and 76 deletions

View File

@@ -41,11 +41,6 @@
<artifactId>jzo2o-knife4j-web</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.jzo2o</groupId>-->
<!-- <artifactId>jzo2o-es</artifactId>-->
<!-- </dependency>-->
<!--单元测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
@@ -63,23 +58,28 @@
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.jzo2o</groupId>
<artifactId>jzo2o-es</artifactId>
</dependency>
<dependency>
<groupId>com.jzo2o</groupId>
<artifactId>jzo2o-canal-sync</artifactId>
</dependency>
<dependency>
<groupId>com.jzo2o</groupId>
<artifactId>jzo2o-redis</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.jzo2o</groupId>-->
<!-- <artifactId>jzo2o-canal-sync</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>com.jzo2o</groupId>
<artifactId>jzo2o-mysql</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.jzo2o</groupId>-->
<!-- <artifactId>jzo2o-xxl-job</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>com.jzo2o</groupId>
<artifactId>jzo2o-xxl-job</artifactId>
</dependency>
</dependencies>
<build>

View File

@@ -0,0 +1,69 @@
package com.jzo2o.foundations.controller.consumer;
import com.jzo2o.foundations.model.dto.response.ServeAggregationSimpleResDTO;
import com.jzo2o.foundations.model.dto.response.ServeAggregationTypeSimpleResDTO;
import com.jzo2o.foundations.model.dto.response.ServeCategoryResDTO;
import com.jzo2o.foundations.model.dto.response.ServeSimpleResDTO;
import com.jzo2o.foundations.service.IServeService;
import com.jzo2o.foundations.service.IServeTypeService;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* 用户端 - 服务相关接口
* @author JIAN
*/
@RestController("consumerServeController")
@RequestMapping("/customer/serve")
@Api(tags = "用户端 - 服务相关接口")
public class ServeController {
/**
* 获取首页服务类型及服务项
*/
@GetMapping("/firstPageServeList")
public List<ServeCategoryResDTO> getFirstPageServeList(@RequestParam Long regionId) {
return serveService.getFirstPageServeList(regionId);
}
/**
* 获取全部服务类型
*/
@GetMapping("/serveTypeList")
public List<ServeAggregationTypeSimpleResDTO> getServeTypeList(@RequestParam Long regionId) {
return serveTypeService.getServeTypeList(regionId);
}
/**
* 获取热门服务项
*/
@GetMapping("/hotServeList")
public List<ServeAggregationSimpleResDTO> getHotServeList(@RequestParam Long regionId) {
return serveService.getHotServeList(regionId);
}
/**
* 获取指定id的服务详情
*/
@GetMapping("/{id}")
public ServeAggregationSimpleResDTO getServeById(@PathVariable("id") Long serveId) {
return serveService.getServeById(serveId);
}
/**
* 服务查询
*/
@GetMapping("/search")
public List<ServeSimpleResDTO> findServeList(@RequestParam() String cityCode,
@RequestParam(required = false) Long serveTypeId,
@RequestParam(required = false) String keyword) {
return serveService.findServeList(cityCode, serveTypeId, keyword);
}
@Resource
private IServeService serveService;
@Resource
private IServeTypeService serveTypeService;
}

View File

@@ -107,7 +107,6 @@ public class RegionController {
@PutMapping("/refreshRegionRelateCaches/{id}")
@ApiOperation("刷新区域相关缓存")
public void refreshRegionRelateCaches(@PathVariable("id") Long id) {
//todo
// homeService.refreshRegionRelateCaches(id);
regionService.refreshRegionRelateCaches(id);
}
}

View File

@@ -0,0 +1,60 @@
package com.jzo2o.foundations.handler;
import com.jzo2o.canal.listeners.AbstractCanalRabbitMqMsgListener;
import com.jzo2o.es.core.ElasticSearchTemplate;
import com.jzo2o.foundations.constants.IndexConstants;
import com.jzo2o.foundations.model.domain.ServeSync;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
/**
* 接受从Canal发送的MQ消息并解析处理完成ES的索引更新
* @author JIAN
*/
@Slf4j
@Component
public class ServeCanalDataSyncHandler extends AbstractCanalRabbitMqMsgListener<ServeSync> {
/**
* 监听MQ的消息
*/
@RabbitListener(bindings = @QueueBinding(
exchange = @Exchange(name = "exchange.canal-jzo2o", type = ExchangeTypes.TOPIC),
value = @Queue(name = "canal-mq-jzo2o-foundations",
// 限制单消费者保证顺序性
arguments = @Argument(name = "x-single-active-consumer", value = "true", type = "java.lang.Boolean")),
key = "canal-mq-jzo2o-foundations"),
// 限制单进程消费保证顺序性
concurrency = "1")
public void onMessage(Message message) throws Exception {
parseMsg(message);
}
@Resource
private ElasticSearchTemplate elasticSearchTemplate;
@Override
public void batchSave(List<ServeSync> data) {
Boolean isSuccess = elasticSearchTemplate.opsForDoc().batchInsert(IndexConstants.SERVE, data);
log.warn("[batchSave] status: {} data: {}", isSuccess, data.toString());
if (!isSuccess) {
// 通过抛出异常自动发送unack消息
throw new RuntimeException("同步失败");
}
}
@Override
public void batchDelete(List<Long> ids) {
Boolean isSuccess = elasticSearchTemplate.opsForDoc().batchDelete(IndexConstants.SERVE, ids);
log.warn("[batchDelete] status: {} ids: {}", isSuccess, ids.toString());
if (!isSuccess) {
// 通过抛出异常自动发送unack消息
throw new RuntimeException("同步失败");
}
}
}

View File

@@ -0,0 +1,41 @@
package com.jzo2o.foundations.handler;
import com.jzo2o.api.foundations.dto.response.RegionSimpleResDTO;
import com.jzo2o.foundations.constants.RedisConstants;
import com.jzo2o.foundations.service.IRegionService;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
/**
* xxl-job定时任务执行器
* @author JIAN
*/
@Slf4j
@Component
@SuppressWarnings("unused")
public class SpringCacheSyncHandler {
@XxlJob("activeRegionCacheSync")
public void activeRegionCacheSync() {
log.info(">>>>>>>>开始进行缓存同步,更新已启用区域");
// 清理开通服务区域缓存
redisTemplate.delete(RedisConstants.CacheName.JZ_CACHE + "::ACTIVE_REGIONS");
// 更新开通服务区域缓存
List<RegionSimpleResDTO> regionList = regionService.queryActiveRegionListCache();
// 更新每个区域对应的缓存
regionList.forEach(region -> regionService.refreshRegionRelateCaches(region.getId()));
log.info(">>>>>>>>缓存同步结束,完成更新已启用区域");
}
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Resource
private IRegionService regionService;
}

View File

@@ -2,6 +2,8 @@ package com.jzo2o.foundations.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jzo2o.foundations.model.domain.Serve;
import com.jzo2o.foundations.model.dto.response.ServeAggregationSimpleResDTO;
import com.jzo2o.foundations.model.dto.response.ServeCategoryResDTO;
import com.jzo2o.foundations.model.dto.response.ServeResDTO;
import org.apache.ibatis.annotations.Param;
@@ -20,4 +22,16 @@ public interface ServeMapper extends BaseMapper<Serve> {
* @param regionId 区域id
*/
List<ServeResDTO> queryServeListByRegionId(@Param("regionId") Long regionId);
/**
* 区域服务图标查询
* @param regionId 区域id
*/
List<ServeCategoryResDTO> queryServeIconListByRegionId(@Param("regionId") Long regionId);
/**
* 区域热门服务查询
* @param regionId 区域id
*/
List<ServeAggregationSimpleResDTO> queryHotServeListByRegionId(Long regionId);
}

View File

@@ -1,8 +1,10 @@
package com.jzo2o.foundations.mapper;
import com.jzo2o.foundations.model.domain.ServeType;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import com.jzo2o.foundations.model.domain.ServeType;
import com.jzo2o.foundations.model.dto.response.ServeAggregationTypeSimpleResDTO;
import java.util.List;
/**
* <p>
@@ -13,4 +15,8 @@ import org.apache.ibatis.annotations.Mapper;
* @since 2023-07-03
*/
public interface ServeTypeMapper extends BaseMapper<ServeType> {
/**
* 根据区域id查询简略列表
*/
List<ServeAggregationTypeSimpleResDTO> getServeTypeListByRegionId(Long regionId);
}

View File

@@ -3,6 +3,7 @@ package com.jzo2o.foundations.model.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
@@ -19,6 +20,7 @@ import java.math.BigDecimal;
* @since 2023-07-10
*/
@Data
@Builder
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("serve_sync")

View File

@@ -6,7 +6,6 @@ import com.jzo2o.common.model.PageResult;
import com.jzo2o.foundations.model.domain.Region;
import com.jzo2o.foundations.model.dto.request.RegionPageQueryReqDTO;
import com.jzo2o.foundations.model.dto.request.RegionUpsertReqDTO;
import com.jzo2o.foundations.model.dto.response.RegionDisplayResDTO;
import com.jzo2o.foundations.model.dto.response.RegionResDTO;
import java.util.List;
@@ -61,8 +60,9 @@ public interface IRegionService extends IService<Region> {
* 区域启用
*
* @param id 区域id
* @return 用于更新缓存信息
*/
void active(Long id);
List<RegionSimpleResDTO> active(Long id);
/**
* 区域禁用
@@ -78,4 +78,9 @@ public interface IRegionService extends IService<Region> {
*/
List<RegionSimpleResDTO> queryActiveRegionListCache();
/**
* 刷新区域相关的缓存(首页图标、热门服务、服务类型)
* @param id 区域id
*/
void refreshRegionRelateCaches(Long id);
}

View File

@@ -20,6 +20,11 @@ import java.util.List;
* @since 2023-07-03
*/
public interface IServeItemService extends IService<ServeItem> {
/**
* 查询指定id的服务项并缓存
*/
ServeItem selectByIdCache(Long id);
/**
* 服务项新增
*

View File

@@ -5,7 +5,10 @@ import com.jzo2o.common.model.PageResult;
import com.jzo2o.foundations.model.domain.Serve;
import com.jzo2o.foundations.model.dto.request.ServePageQueryReqDTO;
import com.jzo2o.foundations.model.dto.request.ServeUpsertReqDTO;
import com.jzo2o.foundations.model.dto.response.ServeAggregationSimpleResDTO;
import com.jzo2o.foundations.model.dto.response.ServeCategoryResDTO;
import com.jzo2o.foundations.model.dto.response.ServeResDTO;
import com.jzo2o.foundations.model.dto.response.ServeSimpleResDTO;
import java.math.BigDecimal;
import java.util.List;
@@ -15,6 +18,11 @@ import java.util.List;
* @author JIAN
*/
public interface IServeService extends IService<Serve> {
/**
* 查询指定id的服务并缓存
*/
Serve selectByIdCache(Long id);
/**
* 区域服务分页查询
* @param servePageQueryReqDTO 分页参数
@@ -40,7 +48,7 @@ public interface IServeService extends IService<Serve> {
/**
* 设置指定的服务下架
*/
Serve updateOffSale(Long id);
void updateOffSale(Long id);
/**
* 删除指定的服务
@@ -50,10 +58,32 @@ public interface IServeService extends IService<Serve> {
/**
* 设置指定服务热门
*/
Serve updateOnHot(Long id);
void updateOnHot(Long id);
/**
* 取消指定服务热门
*/
Serve updateOffHot(Long id);
void updateOffHot(Long id);
/**
* 获取首页服务类型及服务项
* @param regionId 地区id
*/
List<ServeCategoryResDTO> getFirstPageServeList(Long regionId);
/**
* 获取首页热门服务
* @param regionId 地区id
*/
List<ServeAggregationSimpleResDTO> getHotServeList(Long regionId);
/**
* 获取指定id的服务
*/
ServeAggregationSimpleResDTO getServeById(Long serveId);
/**
* 查询指定区域的服务
*/
List<ServeSimpleResDTO> findServeList(String cityCode, Long serveTypeId, String keyword);
}

View File

@@ -6,6 +6,7 @@ import com.jzo2o.common.model.PageResult;
import com.jzo2o.foundations.model.domain.ServeType;
import com.jzo2o.foundations.model.dto.request.ServeTypePageQueryReqDTO;
import com.jzo2o.foundations.model.dto.request.ServeTypeUpsertReqDTO;
import com.jzo2o.foundations.model.dto.response.ServeAggregationTypeSimpleResDTO;
import com.jzo2o.foundations.model.dto.response.ServeTypeResDTO;
import java.util.List;
@@ -67,4 +68,9 @@ public interface IServeTypeService extends IService<ServeType> {
* @return 服务类型列表
*/
List<ServeTypeSimpleResDTO> queryServeTypeListByActiveStatus(Integer activeStatus);
/**
* 根据区域id查询简略列表
*/
List<ServeAggregationTypeSimpleResDTO> getServeTypeList(Long regionId);
}

View File

@@ -23,8 +23,11 @@ import com.jzo2o.foundations.model.dto.request.RegionUpsertReqDTO;
import com.jzo2o.foundations.model.dto.response.RegionResDTO;
import com.jzo2o.foundations.service.IConfigRegionService;
import com.jzo2o.foundations.service.IRegionService;
import com.jzo2o.foundations.service.IServeService;
import com.jzo2o.foundations.service.IServeTypeService;
import com.jzo2o.mysql.utils.PageUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
@@ -47,6 +50,10 @@ public class RegionServiceImpl extends ServiceImpl<RegionMapper, Region> impleme
private CityDirectoryMapper cityDirectoryMapper;
@Resource
private ServeMapper serveMapper;
@Resource
private IServeService serveService;
@Resource
private IServeTypeService serveTypeService;
/**
* 区域新增
@@ -151,9 +158,9 @@ public class RegionServiceImpl extends ServiceImpl<RegionMapper, Region> impleme
@CacheEvict(value = RedisConstants.CacheName.JZ_CACHE, key = "'ACTIVE_REGIONS'", beforeInvocation = true),
@CacheEvict(value = RedisConstants.CacheName.SERVE_ICON, key = "#id", beforeInvocation = true),
@CacheEvict(value = RedisConstants.CacheName.HOT_SERVE, key = "#id", beforeInvocation = true),
@CacheEvict(value = RedisConstants.CacheName.SERVE_TYPE, key = "#id", beforeInvocation = true)
})
public void active(Long id) {
@CacheEvict(value = RedisConstants.CacheName.SERVE_TYPE, key = "#id", beforeInvocation = true)},
put = @CachePut(value = RedisConstants.CacheName.JZ_CACHE, key = "'ACTIVE_REGIONS'"))
public List<RegionSimpleResDTO> active(Long id) {
// 区域信息
Region region = baseMapper.selectById(id);
// 启用状态
@@ -176,8 +183,10 @@ public class RegionServiceImpl extends ServiceImpl<RegionMapper, Region> impleme
.set(Region::getActiveStatus, FoundationStatusEnum.ENABLE.getStatus());
update(updateWrapper);
//3.如果是启用操作,刷新缓存:启用区域列表、首页图标、热门服务、服务类型
// todo
// 刷新区域相关缓存
this.refreshRegionRelateCaches(id);
// 通过返回值更新开通服务区域缓存
return queryActiveRegionList();
}
/**
@@ -190,8 +199,7 @@ public class RegionServiceImpl extends ServiceImpl<RegionMapper, Region> impleme
@CacheEvict(value = RedisConstants.CacheName.JZ_CACHE, key = "'ACTIVE_REGIONS'", beforeInvocation = true),
@CacheEvict(value = RedisConstants.CacheName.SERVE_ICON, key = "#id", beforeInvocation = true),
@CacheEvict(value = RedisConstants.CacheName.HOT_SERVE, key = "#id", beforeInvocation = true),
@CacheEvict(value = RedisConstants.CacheName.SERVE_TYPE, key = "#id", beforeInvocation = true)
})
@CacheEvict(value = RedisConstants.CacheName.SERVE_TYPE, key = "#id", beforeInvocation = true)})
public void deactivate(Long id) {
// 区域信息
Region region = baseMapper.selectById(id);
@@ -228,4 +236,19 @@ public class RegionServiceImpl extends ServiceImpl<RegionMapper, Region> impleme
return queryActiveRegionList();
}
@Override
@Caching(evict = {
@CacheEvict(value = RedisConstants.CacheName.SERVE_ICON, key = "#id", beforeInvocation = true),
@CacheEvict(value = RedisConstants.CacheName.HOT_SERVE, key = "#id", beforeInvocation = true),
@CacheEvict(value = RedisConstants.CacheName.SERVE_TYPE, key = "#id", beforeInvocation = true)})
public void refreshRegionRelateCaches(Long id) {
// 更新每个区域对应的首页服务列表
serveService.getFirstPageServeList(id);
// 更新每个区域对应的服务类型列表
serveTypeService.getServeTypeList(id);
// 更新每个区域对应的热门服务列表
serveService.getHotServeList(id);
}
}

View File

@@ -28,6 +28,7 @@ import com.jzo2o.foundations.service.IServeSyncService;
import com.jzo2o.mysql.utils.PageHelperUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -53,6 +54,12 @@ public class ServeItemServiceImpl extends ServiceImpl<ServeItemMapper, ServeItem
@Resource
private ServeMapper serveMapper;
@Override
@Cacheable(value = RedisConstants.CacheName.SERVE_ITEM, key = "#id", cacheManager = RedisConstants.CacheManager.ONE_DAY)
public ServeItem selectByIdCache(Long id) {
return baseMapper.selectById(id);
}
/**
* 服务项新增
*

View File

@@ -1,29 +1,48 @@
package com.jzo2o.foundations.service.impl;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
import com.jzo2o.common.expcetions.CommonException;
import com.jzo2o.common.expcetions.ForbiddenOperationException;
import com.jzo2o.common.model.PageResult;
import com.jzo2o.common.utils.BeanUtils;
import com.jzo2o.common.utils.CollUtils;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.es.core.ElasticSearchTemplate;
import com.jzo2o.es.utils.SearchResponseUtils;
import com.jzo2o.foundations.constants.RedisConstants;
import com.jzo2o.foundations.enums.FoundationStatusEnum;
import com.jzo2o.foundations.enums.HotStatusEnum;
import com.jzo2o.foundations.mapper.RegionMapper;
import com.jzo2o.foundations.mapper.ServeItemMapper;
import com.jzo2o.foundations.mapper.ServeMapper;
import com.jzo2o.foundations.model.domain.Serve;
import com.jzo2o.foundations.model.domain.ServeItem;
import com.jzo2o.foundations.mapper.ServeSyncMapper;
import com.jzo2o.foundations.model.domain.*;
import com.jzo2o.foundations.model.dto.request.ServePageQueryReqDTO;
import com.jzo2o.foundations.model.dto.request.ServeUpsertReqDTO;
import com.jzo2o.foundations.model.dto.response.ServeAggregationSimpleResDTO;
import com.jzo2o.foundations.model.dto.response.ServeCategoryResDTO;
import com.jzo2o.foundations.model.dto.response.ServeResDTO;
import com.jzo2o.foundations.model.dto.response.ServeSimpleResDTO;
import com.jzo2o.foundations.service.IRegionService;
import com.jzo2o.foundations.service.IServeItemService;
import com.jzo2o.foundations.service.IServeService;
import com.jzo2o.foundations.service.IServeTypeService;
import com.jzo2o.mysql.utils.PageHelperUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* 区域服务实现类
@@ -31,6 +50,12 @@ import java.util.List;
*/
@Service
public class ServeServiceImpl extends ServiceImpl<ServeMapper, Serve> implements IServeService {
@Override
@Cacheable(value = RedisConstants.CacheName.SERVE, key = "#id", cacheManager = RedisConstants.CacheManager.ONE_DAY)
public Serve selectByIdCache(Long id) {
return baseMapper.selectById(id);
}
@Override
public PageResult<ServeResDTO> page(ServePageQueryReqDTO servePageQueryReqDTO) {
return PageHelperUtils.selectPage(servePageQueryReqDTO,
@@ -43,7 +68,7 @@ public class ServeServiceImpl extends ServiceImpl<ServeMapper, Serve> implements
for (ServeUpsertReqDTO serveItemDTO : serveItems) {
// 服务项校验
Long serveItemId = serveItemDTO.getServeItemId();
ServeItem serveItem = serveItemMapper.selectById(serveItemId);
ServeItem serveItem = serveItemService.getById(serveItemId);
if (ObjectUtils.isEmpty(serveItem)) {
throw new ForbiddenOperationException("服务项不存在");
}
@@ -62,7 +87,7 @@ public class ServeServiceImpl extends ServiceImpl<ServeMapper, Serve> implements
}
Serve serve = BeanUtils.toBean(serveItemDTO, Serve.class);
serve.setCityCode(regionMapper.selectById(regionId).getCityCode());
serve.setCityCode(regionService.getById(regionId).getCityCode());
baseMapper.insert(serve);
}
}
@@ -81,6 +106,7 @@ public class ServeServiceImpl extends ServiceImpl<ServeMapper, Serve> implements
@Override
@Transactional
@CachePut(value = RedisConstants.CacheName.SERVE, key = "#id", unless = "#result.saleStatus != 2", cacheManager = RedisConstants.CacheManager.ONE_DAY)
public Serve updatePrice(Long id, BigDecimal price) {
// 区域服务检验
Serve serve = getServeByIdIfExist(id);
@@ -92,12 +118,20 @@ public class ServeServiceImpl extends ServiceImpl<ServeMapper, Serve> implements
throw new CommonException("价格更新失败");
}
// 更新sync数据同步ES
ChainWrappers.lambdaUpdateChain(serveSyncMapper)
.eq(ServeSync::getId, id)
.set(ServeSync::getPrice, price)
.update();
// 返回修改后对象同步缓存
serve.setPrice(price);
return serve;
}
@Override
@Transactional
@CachePut(value = RedisConstants.CacheName.SERVE, key = "#id", cacheManager = RedisConstants.CacheManager.ONE_DAY)
public Serve updateOnSale(Long id) {
// 区域服务检验
Serve serve = getServeByIdIfExist(id);
@@ -108,7 +142,7 @@ public class ServeServiceImpl extends ServiceImpl<ServeMapper, Serve> implements
throw new ForbiddenOperationException("草稿或下架状态才能上架");
}
Integer activeStatus = serveItemMapper.selectById(serve.getServeItemId()).getActiveStatus();
Integer activeStatus = serveItemService.getById(serve.getServeItemId()).getActiveStatus();
if (!ObjectUtils.equal(activeStatus, FoundationStatusEnum.ENABLE.getStatus())) {
throw new ForbiddenOperationException("对应的服务项未启用不能上架");
}
@@ -121,13 +155,42 @@ public class ServeServiceImpl extends ServiceImpl<ServeMapper, Serve> implements
throw new CommonException("状态更新失败");
}
// 更新服务启用状态
serve.setSaleStatus(enableStatus);
// 服务项信息
ServeItem serveItem = serveItemService.getById(serve.getServeItemId());
// 服务类型
ServeType serveType = serveTypeService.getById(serveItem.getServeTypeId());
// 插入sync表添加ES索引
serveSyncMapper.insert(ServeSync.builder()
// serve_type data
.serveTypeId(serveType.getId())
.serveTypeName(serveType.getName())
.serveItemIcon(serveType.getServeTypeIcon())
.serveTypeImg(serveType.getImg())
.serveTypeSortNum(serveType.getSortNum())
// serve_item data
.serveItemId(serveItem.getId())
.serveItemName(serveItem.getName())
.serveItemIcon(serveItem.getServeItemIcon())
.serveItemImg(serveItem.getImg())
.serveItemSortNum(serveItem.getSortNum())
.unit(serveItem.getUnit())
.detailImg(serveItem.getDetailImg())
// serve data
.id(serve.getId())
.price(serve.getPrice())
.cityCode(serve.getCityCode())
.isHot(serve.getIsHot()).build());
return serve;
}
@Override
@Transactional
public Serve updateOffSale(Long id) {
@CacheEvict(value = RedisConstants.CacheName.SERVE, key = "#id", cacheManager = RedisConstants.CacheManager.ONE_DAY)
public void updateOffSale(Long id) {
// 区域服务检验
Serve serve = getServeByIdIfExist(id);
@@ -144,8 +207,8 @@ public class ServeServiceImpl extends ServiceImpl<ServeMapper, Serve> implements
throw new CommonException("状态更新失败");
}
serve.setSaleStatus(disableStatus);
return serve;
// 删除sync表数据删除ES索引
serveSyncMapper.deleteById(id);
}
@Override
@@ -163,7 +226,7 @@ public class ServeServiceImpl extends ServiceImpl<ServeMapper, Serve> implements
@Override
@Transactional
public Serve updateOnHot(Long id) {
public void updateOnHot(Long id) {
Serve serve = getServeByIdIfExist(id);
if (serve.getIsHot() != HotStatusEnum.OFF_HOT.getStatus()) {
@@ -177,14 +240,11 @@ public class ServeServiceImpl extends ServiceImpl<ServeMapper, Serve> implements
.update()) {
throw new CommonException("热门状态更新失败");
}
serve.setIsHot(hotStatus);
return serve;
}
@Override
@Transactional
public Serve updateOffHot(Long id) {
public void updateOffHot(Long id) {
Serve serve = getServeByIdIfExist(id);
if (serve.getIsHot() != HotStatusEnum.ON_HOT.getStatus()) {
@@ -198,14 +258,138 @@ public class ServeServiceImpl extends ServiceImpl<ServeMapper, Serve> implements
.update()) {
throw new CommonException("热门状态更新失败");
}
}
serve.setIsHot(hotStatus);
return serve;
@Override
@Caching(cacheable = {
@Cacheable(value = RedisConstants.CacheName.SERVE_ICON, key = "#regionId",
cacheManager = RedisConstants.CacheManager.THIRTY_MINUTES,
unless = "#result.size() != 0"), // 防止缓存穿透
@Cacheable(value = RedisConstants.CacheName.SERVE_ICON, key = "#regionId",
cacheManager = RedisConstants.CacheManager.FOREVER,
unless = "#result.size() == 0")})
public List<ServeCategoryResDTO> getFirstPageServeList(Long regionId) {
Region region = regionService.getById(regionId);
if (ObjectUtils.isEmpty(region)) {
return Collections.emptyList();
}
List<ServeCategoryResDTO> serveIconList = baseMapper.queryServeIconListByRegionId(regionId);
if (CollUtils.isEmpty(serveIconList)) {
return Collections.emptyList();
}
// 保留最多前两个类型及最多前4个服务项
serveIconList = new ArrayList<>(serveIconList.subList(0, Math.min(serveIconList.size(), 2)));
serveIconList.forEach(res -> {
List<ServeSimpleResDTO> serveResDTOList = res.getServeResDTOList();
res.setServeResDTOList(new ArrayList<>(serveResDTOList.subList(0, Math.min(serveResDTOList.size(), 4))));
});
return serveIconList;
}
@Override
@Caching(cacheable = {
@Cacheable(value = RedisConstants.CacheName.HOT_SERVE, key = "#regionId",
cacheManager = RedisConstants.CacheManager.THIRTY_MINUTES,
unless = "#result.size() != 0"), // 防止缓存穿透
@Cacheable(value = RedisConstants.CacheName.HOT_SERVE, key = "#regionId",
cacheManager = RedisConstants.CacheManager.FOREVER,
unless = "#result.size() == 0")})
public List<ServeAggregationSimpleResDTO> getHotServeList(Long regionId) {
Region region = regionService.getById(regionId);
if (ObjectUtils.isEmpty(region)) {
return Collections.emptyList();
}
List<ServeAggregationSimpleResDTO> hotServeList = baseMapper.queryHotServeListByRegionId(regionId);
if (CollUtils.isEmpty(hotServeList)) {
return Collections.emptyList();
}
return hotServeList;
}
@Override
public ServeAggregationSimpleResDTO getServeById(Long serveId) {
Serve serve = serveService.selectByIdCache(serveId);
if (ObjectUtils.isEmpty(serve)) {
return new ServeAggregationSimpleResDTO();
}
ServeItem serveItem = serveItemService.selectByIdCache(serve.getServeItemId());
if (ObjectUtils.isEmpty(serveItem)) {
return new ServeAggregationSimpleResDTO();
}
return ServeAggregationSimpleResDTO.builder()
.id(serve.getId())
.serveItemId(serveItem.getId())
.serveItemName(serveItem.getName())
.serveItemImg(serveItem.getImg())
.detailImg(serveItem.getDetailImg())
.unit(serveItem.getUnit())
.price(serve.getPrice())
.cityCode(serve.getCityCode())
.build();
}
@Override
public List<ServeSimpleResDTO> findServeList(String cityCode, Long serveTypeId, String keyword) {
// 构建ES搜索请求
SearchRequest searchRequest = new SearchRequest.Builder()
.index("serve_aggregation")
.query(query -> query
.bool(bool -> {
bool = bool.must(must -> must.term(term -> term
.field("city_code")
.value(cityCode)));
if (!ObjectUtils.isEmpty(serveTypeId)) {
bool = bool.must(must -> must.term(term -> term
.field("serve_type_id")
.value(serveTypeId)));
}
if (!ObjectUtils.isEmpty(keyword)) {
bool = bool.must(must -> must.multiMatch(multi -> multi
.query(keyword)
.fields("serve_item_name", "serve_item_name")));
}
return bool;
}))
.sort(sort -> sort
.field(field -> field
.field("serve_item_sort_num")
.order(SortOrder.Asc)))
.build();
// 发送搜索请求获取结果
SearchResponse<ServeAggregation> response = elasticSearchTemplate
.opsForDoc()
.search(searchRequest, ServeAggregation.class);
if (SearchResponseUtils.isNotSuccess(response)) {
return Collections.emptyList();
} else {
return response.hits().hits().stream()
.map(hit -> BeanUtils.toBean(hit.source(), ServeSimpleResDTO.class))
.collect(Collectors.toList());
}
}
@Resource
private ServeItemMapper serveItemMapper;
private IRegionService regionService;
@Resource
private RegionMapper regionMapper;
private IServeService serveService;
@Resource
private IServeTypeService serveTypeService;
@Resource
private IServeItemService serveItemService;
@Resource
private ServeSyncMapper serveSyncMapper;
@Resource
private ElasticSearchTemplate elasticSearchTemplate;
}

View File

@@ -12,21 +12,30 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.api.foundations.dto.response.ServeTypeSimpleResDTO;
import com.jzo2o.common.expcetions.ForbiddenOperationException;
import com.jzo2o.common.model.PageResult;
import com.jzo2o.common.utils.CollUtils;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.foundations.constants.RedisConstants;
import com.jzo2o.foundations.enums.FoundationStatusEnum;
import com.jzo2o.foundations.mapper.RegionMapper;
import com.jzo2o.foundations.mapper.ServeTypeMapper;
import com.jzo2o.foundations.model.domain.Region;
import com.jzo2o.foundations.model.domain.ServeType;
import com.jzo2o.foundations.model.dto.request.ServeSyncUpdateReqDTO;
import com.jzo2o.foundations.model.dto.request.ServeTypePageQueryReqDTO;
import com.jzo2o.foundations.model.dto.request.ServeTypeUpsertReqDTO;
import com.jzo2o.foundations.model.dto.response.ServeAggregationTypeSimpleResDTO;
import com.jzo2o.foundations.model.dto.response.ServeTypeResDTO;
import com.jzo2o.foundations.service.IServeItemService;
import com.jzo2o.foundations.service.IServeSyncService;
import com.jzo2o.foundations.service.IServeTypeService;
import com.jzo2o.mysql.utils.PageUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
/**
@@ -41,6 +50,8 @@ public class ServeTypeServiceImpl extends ServiceImpl<ServeTypeMapper, ServeType
private IServeItemService serveItemService;
@Resource
private IServeSyncService serveSyncService;
@Resource
private RegionMapper regionMapper;
/**
* 服务类型新增
@@ -192,4 +203,26 @@ public class ServeTypeServiceImpl extends ServiceImpl<ServeTypeMapper, ServeType
List<ServeType> serveTypeList = baseMapper.selectList(queryWrapper);
return BeanUtil.copyToList(serveTypeList, ServeTypeSimpleResDTO.class);
}
@Override
@Caching(cacheable = {
@Cacheable(value = RedisConstants.CacheName.SERVE_TYPE, key = "#regionId",
cacheManager = RedisConstants.CacheManager.THIRTY_MINUTES,
unless = "#result.size() != 0"), // 防止缓存穿透
@Cacheable(value = RedisConstants.CacheName.SERVE_TYPE, key = "#regionId",
cacheManager = RedisConstants.CacheManager.FOREVER,
unless = "#result.size() == 0")})
public List<ServeAggregationTypeSimpleResDTO> getServeTypeList(Long regionId) {
Region region = regionMapper.selectById(regionId);
if (ObjectUtils.isEmpty(region)) {
return Collections.emptyList();
}
List<ServeAggregationTypeSimpleResDTO> serveTypeList = baseMapper.getServeTypeListByRegionId(regionId);
if (CollUtils.isEmpty(serveTypeList)) {
return Collections.emptyList();
}
return serveTypeList;
}
}

View File

@@ -41,12 +41,12 @@ spring:
shared-configs: # 共享配置
- data-id: shared-redis-cluster.yaml # 共享redis配置
refresh: false
# - data-id: shared-xxl-job.yaml # xxl-job配置
# refresh: false
# - data-id: shared-rabbitmq.yaml # rabbitmq配置
# refresh: false
# - data-id: shared-es.yaml # rabbitmq配置
# refresh: false
- data-id: shared-xxl-job.yaml # xxl-job配置
refresh: false
- data-id: shared-rabbitmq.yaml # rabbitmq配置
refresh: false
- data-id: shared-es.yaml # elasticsearch配置
refresh: false
- data-id: shared-mysql.yaml # mysql配置
refresh: false

View File

@@ -19,4 +19,56 @@
JOIN serve_type st ON si.serve_type_id = st.id
WHERE s.region_id = #{regionId}
</select>
<resultMap id="ServeCategoryResMap" type="com.jzo2o.foundations.model.dto.response.ServeCategoryResDTO">
<id column="serve_type_id" property="serveTypeId"/>
<result column="type_name" property="serveTypeName"/>
<result column="serve_type_icon" property="serveTypeIcon"/>
<result column="city_code" property="cityCode"/>
<result column="type_sort_num" property="serveTypeSortNum"/>
<collection property="serveResDTOList" ofType="com.jzo2o.foundations.model.dto.response.ServeSimpleResDTO">
<id column="serve_id" property="id"/>
<result column="serve_item_id" property="serveItemId"/>
<result column="item_name" property="serveItemName"/>
<result column="serve_item_icon" property="serveItemIcon"/>
<result column="item_sort_num" property="serveItemSortNum"/>
</collection>
</resultMap>
<select id="queryServeIconListByRegionId" resultMap="ServeCategoryResMap">
SELECT serve_type_id,
type.name type_name,
serve_type_icon,
city_code,
type.sort_num type_sort_num,
serve_item_id,
item.name item_name,
serve_item_icon,
item.sort_num item_sort_num,
serve.id serve_id
FROM serve
JOIN serve_item item ON serve.serve_item_id = item.id
JOIN serve_type type ON item.serve_type_id = type.id
WHERE serve.region_id = #{regionId}
AND serve.sale_status = 2 # 保证上架服务
ORDER BY type.sort_num, item.sort_num
</select>
<select id="queryHotServeListByRegionId"
resultType="com.jzo2o.foundations.model.dto.response.ServeAggregationSimpleResDTO">
SELECT serve.id,
serve_item_id,
name serve_item_name,
img serve_item_img,
unit,
price,
detail_img,
city_code
FROM serve
JOIN serve_item item ON serve.serve_item_id = item.id
WHERE serve.region_id = #{regionId}
AND serve.sale_status = 2 # 保证上架服务
AND serve.is_hot = 1 # 保证热门状态
ORDER BY item.sort_num
</select>
</mapper>

View File

@@ -1,5 +1,17 @@
<?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.jzo2o.foundations.mapper.ServeTypeMapper">
<select id="getServeTypeListByRegionId"
resultType="com.jzo2o.foundations.model.dto.response.ServeAggregationTypeSimpleResDTO">
SELECT distinct serve_type_id,
type.name serveTypeName,
type.img serveTypeImg,
type.sort_num serveTypeSortNum
FROM serve
JOIN serve_item item ON serve.serve_item_id = item.id
JOIN serve_type type ON item.serve_type_id = type.id
WHERE serve.region_id = #{regionId}
AND serve.sale_status = 2 # 保证上架服务
ORDER BY type.sort_num
</select>
</mapper>