diff --git a/admin-web/src/models/promotion/couponCardTemplateList.js b/admin-web/src/models/promotion/couponCardTemplateList.js index ba7735a1b..6de270372 100644 --- a/admin-web/src/models/promotion/couponCardTemplateList.js +++ b/admin-web/src/models/promotion/couponCardTemplateList.js @@ -6,6 +6,7 @@ import { getCouponCardTemplatePage, } from '../../services/promotion'; import PaginationHelper from '../../../helpers/PaginationHelper'; +import {productSpuList, productSpuSearchList} from "../../services/product"; const SEARCH_PARAMS_DEFAULT = { title: '', @@ -26,6 +27,7 @@ export default { modalType: undefined, // 'add' or 'update' 表单 formVals: {}, // 当前表单值 modalLoading: false, + searchProductSpuList: [], }, effects: { @@ -153,6 +155,33 @@ export default { // } // }, + * searchProductSpu({ payload }, { call, put }) { + // 请求 + const response = yield call(productSpuSearchList, payload); + // 响应 + if (response.code === 0) { + yield put({ + type: 'setAll', + payload: { + searchProductSpuList: response.data, + }, + }); + } + }, + + * getProductSpuList({ payload }, { call, put }) { + // 请求 + const response = yield call(productSpuList, payload); + // 响应 + if (response.code === 0) { + yield put({ + type: 'setAll', + payload: { + formSpuValues: response.data, + }, + }); + } + } }, reducers: { diff --git a/admin-web/src/models/promotion/productRecommendList.js b/admin-web/src/models/promotion/productRecommendList.js index d5011e05f..f3e0b63fa 100644 --- a/admin-web/src/models/promotion/productRecommendList.js +++ b/admin-web/src/models/promotion/productRecommendList.js @@ -7,6 +7,7 @@ import { updateProductRecommendStatus, } from '../../services/promotion'; import PaginationHelper from '../../../helpers/PaginationHelper'; +import {productSpuList, productSpuSearchList} from "../../services/product"; const SEARCH_PARAMS_DEFAULT = { type: undefined, @@ -27,6 +28,8 @@ export default { modalType: undefined, // 'add' or 'update' 表单 formVals: {}, // 当前表单值 modalLoading: false, + searchProductSpuList: [], // 搜索商品 + formSpuValues: [], // 编辑时,如果优惠劵选择的是商品,则需要获取该值。 }, effects: { @@ -151,6 +154,19 @@ export default { } }, + * searchProductSpu({ payload }, { call, put }) { + // 请求 + const response = yield call(productSpuSearchList, payload); + // 响应 + if (response.code === 0) { + yield put({ + type: 'setAll', + payload: { + searchProductSpuList: response.data, + }, + }); + } + }, }, reducers: { diff --git a/admin-web/src/pages/Product/ProductSpuList.js b/admin-web/src/pages/Product/ProductSpuList.js index 12242bac3..096cdec46 100644 --- a/admin-web/src/pages/Product/ProductSpuList.js +++ b/admin-web/src/pages/Product/ProductSpuList.js @@ -217,7 +217,7 @@ const SearchForm = Form.create()(props => { - + {getFieldDecorator('cid')( {status[val]}, }, - { - title: '使用说明', - dataIndex: 'description', - }, + // { + // title: '使用说明', + // dataIndex: 'description', + // }, { title: '创建时间', dataIndex: 'createTime', @@ -264,18 +264,20 @@ const SearchForm = Form.create()(props => { // 添加 or 修改 Form 表单 const AddOrUpdateForm = Form.create()(props => { - const { dispatch, modalVisible, form, handleModalVisible, modalType, formVals } = props; + const { dispatch, modalVisible, form, handleModalVisible, modalType, formVals, + searchProductSpuList, formSpuValues, categoryTree} = props; const okHandle = () => { form.validateFields((err, fields) => { if (err) return; - let newFileds = { + let newFields = { ...fields, priceAvailable: fields.priceAvailable ? parseInt(fields.priceAvailable * 100) : undefined, priceOff: fields.priceOff ? parseInt(fields.priceOff * 100) : undefined, discountPriceLimit: fields.discountPriceLimit ? parseInt(fields.discountPriceLimit * 100) : undefined, validStartTime: fields.validStartTime ? fields.validStartTime.format('YYYY-MM-DD') : undefined, - validEndTime: fields.validEndTime ? fields.validEndTime.format('YYYY-MM-DD') : undefined + validEndTime: fields.validEndTime ? fields.validEndTime.format('YYYY-MM-DD') : undefined, + rangeValues: fields.rangeValues && fields.rangeValues.length > 0 ? fields.rangeValues.join(',') : undefined, }; // 添加表单 if (modalType === 'add') { @@ -283,7 +285,7 @@ const AddOrUpdateForm = Form.create()(props => { type: 'couponCardTemplateList/add', payload: { body: { - ...newFileds, + ...newFields, }, callback: () => { // 清空表单 @@ -302,7 +304,7 @@ const AddOrUpdateForm = Form.create()(props => { payload: { body: { id: formVals.id, - ...newFileds, + ...newFields, priceAvailable: undefined, dateType: undefined, validStartTime: undefined, @@ -340,6 +342,42 @@ const AddOrUpdateForm = Form.create()(props => { formVals.preferentialType = parseInt(value); } + const searchProductSpu = (value) => { + if (!value) { + dispatch({ + type: 'couponCardTemplateList/setAll', + payload: { + searchProductSpuList: [], + }, + }); + return; + } + dispatch({ + type: 'couponCardTemplateList/searchProductSpu', + payload: { + name: value, + }, + }); + }; + + // 处理分类筛选 + const buildSelectTree = (list) => { + return list.map(item => { + let children = []; + if (item.children) { + children = buildSelectTree(item.children); + } + return { + title: item.name, + value: item.id, + key: item.id, + children, + selectable: item.pid > 0 + }; + }); + }; + let categoryTreeSelect = buildSelectTree(categoryTree); + const title = modalType === 'add' ? '新建优惠劵' : '更新优惠劵'; return ( { {form.getFieldDecorator('priceAvailable', { rules: [{ required: true, message: '请输入使用金额门槛!' },], - initialValue: formVals.priceAvailable / 100.0, + initialValue: formVals.priceAvailable ? formVals.priceAvailable / 100.0 : undefined, })()} 元 {form.getFieldDecorator('rangeType', { rules: [{ required: true, message: '请选择可用范围!'}, // TODO 芋艿,需要修改 ], - initialValue: formVals.rangeType + '', + initialValue: formVals.rangeType ? formVals.rangeType + '' : undefined, })( )} + {/*{*/} + {/* formVals.rangeType == 20 || formVals.rangeType == 21*/} + {/* || formVals.rangeType == 30 || formVals.rangeType == 31 ?*/} + {/* */} + {/* {form.getFieldDecorator('rangeValues', {*/} + {/* rules: [{ required: true, message: '请输入具体范围!' }, // TODO 芋艿,做成搜索*/} + {/* {maxlength: 255, message: '最大长度为 255 位'},*/} + {/* ],*/} + {/* initialValue: formVals.rangeValues,*/} + {/* })()}*/} + {/* */} + {/* : ''*/} + {/*}*/} { - formVals.rangeType == 20 || formVals.rangeType == 21 - || formVals.rangeType == 30 || formVals.rangeType == 31 ? - + formVals.rangeType == 20 || formVals.rangeType == 21? + {form.getFieldDecorator('rangeValues', { - rules: [{ required: true, message: '请输入具体范围!' }, // TODO 芋艿,做成搜索 - {maxlength: 255, message: '最大长度为 255 位'}, + rules: [{ required: true, message: '请选择商品!' }, ], - initialValue: formVals.rangeValues, - })()} + initialValue: formVals.rangeValues ? formVals.rangeValues.split(',') : undefined, + })( + + )} - : '' + : '' + } + { + formVals.rangeType == 30 || formVals.rangeType == 31 ? + + {form.getFieldDecorator('rangeValues', { + rules: [{ required: true, message: '请选择分类!' }, + ], + initialValue: formVals.rangeValues ? formVals.rangeValues.split(',') : undefined, + })( + + )} + + : '' } {form.getFieldDecorator('dateType', { rules: [{ required: true, message: '请选择可用范围!'}, // TODO 芋艿,需要修改 ], - initialValue: formVals.dateType + '', + initialValue: formVals.dateType ? formVals.dateType + '' : undefined, })( 代金卷 @@ -513,10 +597,11 @@ const AddOrUpdateForm = Form.create()(props => { ); }); -@connect(({ couponCardTemplateList }) => ({ +@connect(({ couponCardTemplateList, productCategoryList }) => ({ // list: productRecommend.list, // pagination: productRecommend.pagination, ...couponCardTemplateList, + categoryTree: productCategoryList.list, })) // 主界面 @@ -525,6 +610,7 @@ class CouponCardTemplateLists extends PureComponent { componentDidMount() { const { dispatch } = this.props; + // 获得优惠劵列表 dispatch({ type: 'couponCardTemplateList/query', payload: { @@ -535,21 +621,40 @@ class CouponCardTemplateLists extends PureComponent { handleModalVisible = (modalVisible, modalType, record) => { const { dispatch } = this.props; + // 弹窗,并清空一些缓存 dispatch({ type: 'couponCardTemplateList/setAll', payload: { modalVisible, modalType, - formVals: record || {} + formVals: record || {}, + searchProductSpuList: [], + formSpuValues: [], }, }); + // 如果是指定商品,则获得商品列表 + if (record && record.rangeType && + (record.rangeType === 20 || record.rangeType === 21)) { + dispatch({ + type: 'couponCardTemplateList/getProductSpuList', + payload: { + ids: record.rangeValues, + }, + }); + } + // 获得商品分类,因为后续可能使用到 + // 获得商品分类 + dispatch({ + type: 'productCategoryList/tree', + payload: {}, + }); }; render() { // let that = this; const { dispatch, list, listLoading, searchParams, pagination, - modalVisible, modalType, formVals, + modalVisible, modalType, formVals, searchProductSpuList, formSpuValues, categoryTree, confirmLoading, } = this.props; // 列表属性 @@ -574,6 +679,9 @@ class CouponCardTemplateLists extends PureComponent { modalType, formVals, dispatch, + searchProductSpuList, + formSpuValues, + categoryTree, handleModalVisible: this.handleModalVisible, // Function }; diff --git a/admin-web/src/pages/Promotion/ProductRecommendList.js b/admin-web/src/pages/Promotion/ProductRecommendList.js index ef673dd40..8b77d02df 100644 --- a/admin-web/src/pages/Promotion/ProductRecommendList.js +++ b/admin-web/src/pages/Promotion/ProductRecommendList.js @@ -211,7 +211,12 @@ const SearchForm = Form.create()(props => { // 添加 or 修改 Form 表单 const AddOrUpdateForm = Form.create()(props => { - const { dispatch, modalVisible, form, handleModalVisible, modalType, formVals } = props; + const { dispatch, modalVisible, form, handleModalVisible, modalType, formVals, + searchProductSpuList} = props; + // let selectedSearchProductSpu = formVals.productSpuId ? { + // key: formVals.productSpuId, + // label: formVals.productSpuName, + // } : {}; const okHandle = () => { form.validateFields((err, fields) => { @@ -257,6 +262,24 @@ const AddOrUpdateForm = Form.create()(props => { }); }; + const searchProductSpu = (value) => { + if (!value) { + dispatch({ + type: 'productRecommendList/setAll', + payload: { + searchProductSpuList: [], + }, + }); + return; + } + dispatch({ + type: 'productRecommendList/searchProductSpu', + payload: { + name: value, + }, + }); + }; + const title = modalType === 'add' ? '新建商品推荐' : '更新商品推荐'; return ( { rules: [{ required: true, message: '请输入商品!'}, // TODO 芋艿,临时先输入商品编号,后面做成搜索。 ], initialValue: formVals.productSpuId, - })()} + })( + + )} {form.getFieldDecorator('sort', { @@ -331,7 +367,8 @@ class BannerList extends PureComponent { payload: { modalVisible, modalType, - formVals: record || {} + formVals: record || {}, + searchProductSpuList: [], }, }); }; @@ -340,7 +377,7 @@ class BannerList extends PureComponent { // let that = this; const { dispatch, list, listLoading, searchParams, pagination, - modalVisible, modalType, formVals, + modalVisible, modalType, formVals, searchProductSpuList, confirmLoading, } = this.props; // 列表属性 @@ -365,6 +402,7 @@ class BannerList extends PureComponent { modalType, formVals, dispatch, + searchProductSpuList, handleModalVisible: this.handleModalVisible, // Function }; diff --git a/admin-web/src/services/product.js b/admin-web/src/services/product.js index 1f120516e..b34721d9b 100644 --- a/admin-web/src/services/product.js +++ b/admin-web/src/services/product.js @@ -44,6 +44,18 @@ export async function productSpuPage(params) { }); } +export async function productSpuSearchList(params) { + return request(`/product-api/admins/spu/search_list?${stringify(params)}`, { + method: 'GET', + }); +} + +export async function productSpuList(params) { + return request(`/product-api/admins/spu/list?${stringify(params)}`, { + method: 'GET', + }); +} + export async function productSpuAdd(params) { return request(`/product-api/admins/spu/add?${stringify(params)}`, { method: 'POST', diff --git a/common/common-framework/pom.xml b/common/common-framework/pom.xml index 5c8c10317..94ad59cb3 100644 --- a/common/common-framework/pom.xml +++ b/common/common-framework/pom.xml @@ -84,6 +84,12 @@ compile + + org.apache.dubbo + dubbo + compile + + diff --git a/common/common-framework/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java b/common/common-framework/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java new file mode 100644 index 000000000..0598b46e9 --- /dev/null +++ b/common/common-framework/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java @@ -0,0 +1,268 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.config.spring.beans.factory.annotation; + +import org.apache.dubbo.config.annotation.Reference; +import org.apache.dubbo.config.spring.ReferenceBean; +import org.apache.dubbo.config.spring.ServiceBean; +import org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent; +import org.apache.dubbo.config.spring.util.AnnotationUtils; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.InjectionMetadata; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation + * that Consumer service {@link Reference} annotated fields + * + * @since 2.5.7 + */ +public class ReferenceAnnotationBeanPostProcessor extends AnnotationInjectedBeanPostProcessor + implements ApplicationContextAware, ApplicationListener { + + /** + * The bean name of {@link ReferenceAnnotationBeanPostProcessor} + */ + public static final String BEAN_NAME = "referenceAnnotationBeanPostProcessor"; + + /** + * Cache size + */ + private static final int CACHE_SIZE = Integer.getInteger(BEAN_NAME + ".cache.size", 32); + + private final ConcurrentMap> referenceBeanCache = + new ConcurrentHashMap>(CACHE_SIZE); + + private final ConcurrentHashMap localReferenceBeanInvocationHandlerCache = + new ConcurrentHashMap(CACHE_SIZE); + + private final ConcurrentMap> injectedFieldReferenceBeanCache = + new ConcurrentHashMap>(CACHE_SIZE); + + private final ConcurrentMap> injectedMethodReferenceBeanCache = + new ConcurrentHashMap>(CACHE_SIZE); + + private ApplicationContext applicationContext; + + /** + * Gets all beans of {@link ReferenceBean} + * + * @return non-null read-only {@link Collection} + * @since 2.5.9 + */ + public Collection> getReferenceBeans() { + return referenceBeanCache.values(); + } + + /** + * Get {@link ReferenceBean} {@link Map} in injected field. + * + * @return non-null {@link Map} + * @since 2.5.11 + */ + public Map> getInjectedFieldReferenceBeanMap() { + return Collections.unmodifiableMap(injectedFieldReferenceBeanCache); + } + + /** + * Get {@link ReferenceBean} {@link Map} in injected method. + * + * @return non-null {@link Map} + * @since 2.5.11 + */ + public Map> getInjectedMethodReferenceBeanMap() { + return Collections.unmodifiableMap(injectedMethodReferenceBeanCache); + } + + @Override + protected Object doGetInjectedBean(Reference reference, Object bean, String beanName, Class injectedType, + InjectionMetadata.InjectedElement injectedElement) throws Exception { + + String referencedBeanName = buildReferencedBeanName(reference, injectedType); + + ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referencedBeanName, reference, injectedType, getClassLoader()); + + cacheInjectedReferenceBean(referenceBean, injectedElement); + + Object proxy = buildProxy(referencedBeanName, referenceBean, injectedType); + + return proxy; + } + + private Object buildProxy(String referencedBeanName, ReferenceBean referenceBean, Class injectedType) { + InvocationHandler handler = buildInvocationHandler(referencedBeanName, referenceBean); + Object proxy = Proxy.newProxyInstance(getClassLoader(), new Class[]{injectedType}, handler); + return proxy; + } + + private InvocationHandler buildInvocationHandler(String referencedBeanName, ReferenceBean referenceBean) { + + ReferenceBeanInvocationHandler handler = localReferenceBeanInvocationHandlerCache.get(referencedBeanName); + + if (handler == null) { + handler = new ReferenceBeanInvocationHandler(referenceBean); + } + + if (applicationContext.containsBean(referencedBeanName)) { // Is local @Service Bean or not ? + // ReferenceBeanInvocationHandler's initialization has to wait for current local @Service Bean has been exported. + localReferenceBeanInvocationHandlerCache.put(referencedBeanName, handler); + } else if (!applicationContext.getBeansOfType(referenceBean.getInterfaceClass()).isEmpty()) { // TODO 芋艿,临时添加,等待官方修复方案 + localReferenceBeanInvocationHandlerCache.put(referencedBeanName, handler); + } else { + // Remote Reference Bean should initialize immediately + handler.init(); + } + + return handler; + } + + private static class ReferenceBeanInvocationHandler implements InvocationHandler { + + private final ReferenceBean referenceBean; + + private Object bean; + + private ReferenceBeanInvocationHandler(ReferenceBean referenceBean) { + this.referenceBean = referenceBean; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + Object result = null; + try { + if (bean == null) { // If the bean is not initialized, invoke init() + // issue: https://github.com/apache/incubator-dubbo/issues/3429 + init(); + } + result = method.invoke(bean, args); + } catch (InvocationTargetException e) { + // re-throws the actual Exception. + throw e.getTargetException(); + } + return result; + } + + private void init() { + this.bean = referenceBean.get(); + } + } + + @Override + protected String buildInjectedObjectCacheKey(Reference reference, Object bean, String beanName, + Class injectedType, InjectionMetadata.InjectedElement injectedElement) { + + String key = buildReferencedBeanName(reference, injectedType) + + "#source=" + (injectedElement.getMember()) + + "#attributes=" + AnnotationUtils.getAttributes(reference,getEnvironment(),true); + + return key; + } + + private String buildReferencedBeanName(Reference reference, Class injectedType) { + + AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(reference, injectedType); + + builder.environment(getEnvironment()); + + return getEnvironment().resolvePlaceholders(builder.build()); + } + + private ReferenceBean buildReferenceBeanIfAbsent(String referencedBeanName, Reference reference, + Class referencedType, ClassLoader classLoader) + throws Exception { + + ReferenceBean referenceBean = referenceBeanCache.get(referencedBeanName); + + if (referenceBean == null) { + ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder + .create(reference, classLoader, applicationContext) + .interfaceClass(referencedType); + referenceBean = beanBuilder.build(); + referenceBeanCache.put(referencedBeanName, referenceBean); + } + + return referenceBean; + } + + private void cacheInjectedReferenceBean(ReferenceBean referenceBean, + InjectionMetadata.InjectedElement injectedElement) { + if (injectedElement.getMember() instanceof Field) { + injectedFieldReferenceBeanCache.put(injectedElement, referenceBean); + } else if (injectedElement.getMember() instanceof Method) { + injectedMethodReferenceBeanCache.put(injectedElement, referenceBean); + } + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + @Override + public void onApplicationEvent(ApplicationEvent event) { + if (event instanceof ServiceBeanExportedEvent) { + onServiceBeanExportEvent((ServiceBeanExportedEvent) event); + } else if (event instanceof ContextRefreshedEvent) { + onContextRefreshedEvent((ContextRefreshedEvent) event); + } + } + + private void onServiceBeanExportEvent(ServiceBeanExportedEvent event) { + ServiceBean serviceBean = event.getServiceBean(); + initReferenceBeanInvocationHandler(serviceBean); + } + + private void initReferenceBeanInvocationHandler(ServiceBean serviceBean) { + String serviceBeanName = serviceBean.getBeanName(); + // Remove ServiceBean when it's exported + ReferenceBeanInvocationHandler handler = localReferenceBeanInvocationHandlerCache.remove(serviceBeanName); + // Initialize + if (handler != null) { + handler.init(); + } + } + + private void onContextRefreshedEvent(ContextRefreshedEvent event) { + + } + + + @Override + public void destroy() throws Exception { + super.destroy(); + this.referenceBeanCache.clear(); + this.localReferenceBeanInvocationHandlerCache.clear(); + this.injectedFieldReferenceBeanCache.clear(); + this.injectedMethodReferenceBeanCache.clear(); + } +} diff --git a/docs/guides/功能列表/功能列表-H5 商城.md b/docs/guides/功能列表/功能列表-H5 商城.md index 35897da11..56f33d3ed 100644 --- a/docs/guides/功能列表/功能列表-H5 商城.md +++ b/docs/guides/功能列表/功能列表-H5 商城.md @@ -4,6 +4,8 @@ * 未完成的功能,欢迎一起来开发,特别是【待认领】的任务。 - [x] 首页 + - [x] 首页广告 + - [x] 商品推荐(手动) - 商品相关 - [x] 分类列表 - [x] 商品搜索 diff --git a/docs/guides/功能列表/功能列表-管理后台.md b/docs/guides/功能列表/功能列表-管理后台.md index 22b0355e9..8ba7696d3 100644 --- a/docs/guides/功能列表/功能列表-管理后台.md +++ b/docs/guides/功能列表/功能列表-管理后台.md @@ -22,12 +22,12 @@ - TODO 需要补充 - [ ] 营销管理 - [x] 首页广告 - - [ ] 优惠劵 + - [x] 商品推荐 + - [x] 优惠劵 - [ ] 优惠码【待认领】 - - [ ] 商品推荐 - - [ ] 满减送活动 - - [ ] 限制折扣活动 - - [ ] 团购活动【待认领】 + - [ ] 满减送 + - [ ] 限制折扣 + - [ ] 多人拼团【待认领】 - [ ] 系统管理 - [ ] 员工管理 - [ ] 角色管理 diff --git a/pay/pay-service-impl/src/test/java/cn/iocoder/mall/pay/biz/Application.java b/pay/pay-service-impl/src/test/java/cn/iocoder/mall/pay/biz/Application.java new file mode 100644 index 000000000..dbdbf1170 --- /dev/null +++ b/pay/pay-service-impl/src/test/java/cn/iocoder/mall/pay/biz/Application.java @@ -0,0 +1,7 @@ +package cn.iocoder.mall.pay.biz; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication(scanBasePackages = {"cn.iocoder.mall.pay"}) +public class Application { +} diff --git a/product/product-application/src/main/java/cn/iocoder/mall/product/application/config/MVCConfiguration.java b/product/product-application/src/main/java/cn/iocoder/mall/product/application/config/MVCConfiguration.java index 494ac25e7..6af4471ff 100644 --- a/product/product-application/src/main/java/cn/iocoder/mall/product/application/config/MVCConfiguration.java +++ b/product/product-application/src/main/java/cn/iocoder/mall/product/application/config/MVCConfiguration.java @@ -20,12 +20,6 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; AdminSecurityInterceptor.class, AdminAccessLogInterceptor.class}) public class MVCConfiguration implements WebMvcConfigurer { -// @Autowired -// private SecurityInterceptor securityInterceptor; - -// @Reference -// private OAuth2Service oauth2Service; - @Autowired private AdminSecurityInterceptor adminSecurityInterceptor; @Autowired diff --git a/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/admins/AdminsProductAttrController.java b/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/admins/AdminsProductAttrController.java index cbf31d969..cd1693fab 100644 --- a/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/admins/AdminsProductAttrController.java +++ b/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/admins/AdminsProductAttrController.java @@ -13,30 +13,29 @@ import cn.iocoder.mall.product.application.vo.admins.AdminsProductAttrPageVO; import cn.iocoder.mall.product.application.vo.admins.AdminsProductAttrSimpleVO; import cn.iocoder.mall.product.application.vo.admins.AdminsProductAttrVO; import cn.iocoder.mall.product.application.vo.admins.AdminsProductAttrValueVO; -import org.apache.dubbo.config.annotation.Reference; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; -import org.springframework.beans.factory.annotation.Autowired; +import org.apache.dubbo.config.annotation.Reference; import org.springframework.web.bind.annotation.*; import java.util.List; -import static cn.iocoder.common.framework.vo.CommonResult.*; + +import static cn.iocoder.common.framework.vo.CommonResult.success; @RestController @RequestMapping("admins") @Api("商品规格") public class AdminsProductAttrController { - @Reference(validation = "true") - @Autowired + @Reference(validation = "true", version = "${dubbo.provider.ProductAttrService.version}") private ProductAttrService productAttrService; @GetMapping("/attr/page") @ApiOperation("获得规格分页") public CommonResult attrPage(@RequestParam(value = "name", required = false) String name, - @RequestParam(value = "pageNo", defaultValue = "0") Integer pageNo, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) { // 创建 ProductAttrPageDTO 对象 ProductAttrPageDTO productAttrPageDTO = new ProductAttrPageDTO().setName(name).setPageNo(pageNo).setPageSize(pageSize); diff --git a/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/admins/AdminsProductCategoryController.java b/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/admins/AdminsProductCategoryController.java index 9f0465289..b02a271f3 100644 --- a/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/admins/AdminsProductCategoryController.java +++ b/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/admins/AdminsProductCategoryController.java @@ -15,7 +15,6 @@ import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import org.apache.dubbo.config.annotation.Reference; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; @@ -31,8 +30,7 @@ import static cn.iocoder.common.framework.vo.CommonResult.success; @Api("商品分类") public class AdminsProductCategoryController { - @Reference(validation = "true") - @Autowired + @Reference(validation = "true", version = "${dubbo.provider.ProductCategoryService.version}") private ProductCategoryService productCategoryService; @GetMapping("/tree") diff --git a/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/admins/AdminsProductSpuController.java b/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/admins/AdminsProductSpuController.java index ed4e65a6b..e167e5db8 100644 --- a/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/admins/AdminsProductSpuController.java +++ b/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/admins/AdminsProductSpuController.java @@ -3,26 +3,23 @@ package cn.iocoder.mall.product.application.controller.admins; import cn.iocoder.common.framework.vo.CommonResult; import cn.iocoder.mall.admin.sdk.context.AdminSecurityContextHolder; import cn.iocoder.mall.product.api.ProductSpuService; +import cn.iocoder.mall.product.api.bo.ProductSpuBO; import cn.iocoder.mall.product.api.bo.ProductSpuDetailBO; import cn.iocoder.mall.product.api.bo.ProductSpuPageBO; -import cn.iocoder.mall.product.api.dto.ProductSkuAddOrUpdateDTO; -import cn.iocoder.mall.product.api.dto.ProductSpuAddDTO; -import cn.iocoder.mall.product.api.dto.ProductSpuPageDTO; -import cn.iocoder.mall.product.api.dto.ProductSpuUpdateDTO; +import cn.iocoder.mall.product.api.dto.*; import cn.iocoder.mall.product.application.convert.ProductSpuConvert; import cn.iocoder.mall.product.application.vo.admins.AdminsProductSpuDetailVO; import cn.iocoder.mall.product.application.vo.admins.AdminsProductSpuPageVO; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.ObjectMapper; +import cn.iocoder.mall.product.application.vo.admins.AdminsProductSpuVO; +import com.alibaba.fastjson.JSON; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import org.apache.dubbo.config.annotation.Reference; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; -import java.io.IOException; +import java.util.Collection; import java.util.List; import static cn.iocoder.common.framework.vo.CommonResult.success; @@ -32,13 +29,9 @@ import static cn.iocoder.common.framework.vo.CommonResult.success; @Api("商品 SPU + SKU") public class AdminsProductSpuController { - @Reference(validation = "true") - @Autowired + @Reference(validation = "true", version = "${dubbo.provider.ProductSpuService.version}") private ProductSpuService productSpuService; - @Autowired - private ObjectMapper objectMapper; // jackson 解析 - @PostMapping("/spu/add") @ApiOperation("创建商品") @ApiImplicitParams({ @@ -109,15 +102,15 @@ public class AdminsProductSpuController { @ApiOperation("商品 SPU 分页列表") @ApiImplicitParams({ @ApiImplicitParam(name = "name", value = "商品名称,模糊匹配", example = "小王"), - @ApiImplicitParam(name = "pageNo", value = "页码,从 1 开始", example = "1"), @ApiImplicitParam(name = "status", value = "状态", example = "可选值:1-在售中;2-已售罄;3-仓库中;"), @ApiImplicitParam(name = "cid", value = "商品分类编号", example = "10"), + @ApiImplicitParam(name = "pageNo", value = "页码,从 1 开始", example = "1"), @ApiImplicitParam(name = "pageSize", value = "每页条数", required = true, example = "10"), }) public CommonResult spuPage(@RequestParam(value = "name", required = false) String name, @RequestParam(value = "status") Integer status, @RequestParam(value = "cid", required = false) Integer cid, - @RequestParam(value = "pageNo", defaultValue = "0") Integer pageNo, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) { // 创建 ProductSpuPageDTO 对象 ProductSpuPageDTO productSpuPageDTO = new ProductSpuPageDTO().setName(name).setCid(cid).setPageNo(pageNo).setPageSize(pageSize); @@ -136,20 +129,40 @@ public class AdminsProductSpuController { return success(ProductSpuConvert.INSTANCE.convert2(result)); } + @GetMapping("/spu/search_list") + @ApiOperation("商品 SPU 搜索列表") + @ApiImplicitParams({ + @ApiImplicitParam(name = "name", value = "商品名称,模糊匹配", example = "小王"), + }) + public CommonResult> spuSearchList(@RequestParam(value = "name", required = false) String name) { + // 创建 ProductSpuSearchListDTO 对象 + ProductSpuSearchListDTO productSpuSearchListDTO = new ProductSpuSearchListDTO().setName(name); + // 执行搜索 + List list = productSpuService.getProductSpuSearchList(productSpuSearchListDTO); + // 转换返回 + return success(ProductSpuConvert.INSTANCE.convert3(list)); + } + @GetMapping("/spu/info") @ApiOperation("商品 SPU 明细") @ApiImplicitParam(name = "id", value = "SPU 编号", required = true, example = "100") - public CommonResult info(@RequestParam("id") Integer id) { + public CommonResult spuInfo(@RequestParam("id") Integer id) { return success(ProductSpuConvert.INSTANCE.convert(productSpuService.getProductSpuDetail(id))); } + @GetMapping("/spu/list") + @ApiOperation("商品 SPU 列表") + @ApiImplicitParams({ + @ApiImplicitParam(name = "ids", value = "商品 SPU 编号数组", example = "1,2,3"), + }) + public CommonResult> spuList(@RequestParam("ids") Collection ids) { + List list = productSpuService.getProductSpuList(ids); + // 转换返回 + return success(ProductSpuConvert.INSTANCE.convert3(list)); + } + private List parseSkus(String skuStr, Class clazz) { - JavaType type = objectMapper.getTypeFactory().constructParametricType(List.class, clazz); - try { - return objectMapper.readValue(skuStr, type); - } catch (IOException e) { - throw new RuntimeException(e); - } + return JSON.parseArray(skuStr, clazz); } } diff --git a/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/users/UsersProductCategoryController.java b/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/users/UsersProductCategoryController.java index 3c4ef1287..e9a9543e8 100644 --- a/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/users/UsersProductCategoryController.java +++ b/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/users/UsersProductCategoryController.java @@ -23,7 +23,7 @@ import java.util.List; @Api("商品分类") public class UsersProductCategoryController { - @Reference(validation = "true") + @Reference(validation = "true", version = "${dubbo.provider.ProductCategoryService.version}") @Autowired private ProductCategoryService productCategoryService; diff --git a/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/users/UsersProductSpuController.java b/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/users/UsersProductSpuController.java index 4cfaf4021..6aece9804 100644 --- a/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/users/UsersProductSpuController.java +++ b/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/users/UsersProductSpuController.java @@ -8,12 +8,11 @@ import cn.iocoder.mall.product.application.convert.ProductSpuConvert; import cn.iocoder.mall.product.application.vo.users.UsersProductSpuDetailVO; import cn.iocoder.mall.product.application.vo.users.UsersProductSpuPageVO; import cn.iocoder.mall.user.sdk.annotation.PermitAll; -import org.apache.dubbo.config.annotation.Reference; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; -import org.springframework.beans.factory.annotation.Autowired; +import org.apache.dubbo.config.annotation.Reference; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -26,8 +25,7 @@ import static cn.iocoder.common.framework.vo.CommonResult.success; @Api("商品 SPU + SKU") public class UsersProductSpuController { - @Reference(validation = "true") - @Autowired + @Reference(validation = "true", version = "${dubbo.provider.ProductSpuService.version}") private ProductSpuService productSpuService; @GetMapping("/info") diff --git a/product/product-application/src/main/java/cn/iocoder/mall/product/application/convert/ProductSpuConvert.java b/product/product-application/src/main/java/cn/iocoder/mall/product/application/convert/ProductSpuConvert.java index d3e88ee39..ce6b00d03 100644 --- a/product/product-application/src/main/java/cn/iocoder/mall/product/application/convert/ProductSpuConvert.java +++ b/product/product-application/src/main/java/cn/iocoder/mall/product/application/convert/ProductSpuConvert.java @@ -1,15 +1,19 @@ package cn.iocoder.mall.product.application.convert; +import cn.iocoder.mall.product.api.bo.ProductSpuBO; import cn.iocoder.mall.product.api.bo.ProductSpuDetailBO; import cn.iocoder.mall.product.api.bo.ProductSpuPageBO; import cn.iocoder.mall.product.application.vo.admins.AdminsProductSpuDetailVO; import cn.iocoder.mall.product.application.vo.admins.AdminsProductSpuPageVO; +import cn.iocoder.mall.product.application.vo.admins.AdminsProductSpuVO; import cn.iocoder.mall.product.application.vo.users.UsersProductSpuDetailVO; import cn.iocoder.mall.product.application.vo.users.UsersProductSpuPageVO; import org.mapstruct.Mapper; import org.mapstruct.Mappings; import org.mapstruct.factory.Mappers; +import java.util.List; + @Mapper public interface ProductSpuConvert { @@ -24,6 +28,9 @@ public interface ProductSpuConvert { @Mappings({}) AdminsProductSpuPageVO convert2(ProductSpuPageBO result); + @Mappings({}) + List convert3(List result); + @Mappings({}) UsersProductSpuPageVO convert3(ProductSpuPageBO result); diff --git a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/ProductSpuService.java b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/ProductSpuService.java index 3f5ed28ad..68f3ae6c2 100644 --- a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/ProductSpuService.java +++ b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/ProductSpuService.java @@ -3,6 +3,7 @@ package cn.iocoder.mall.product.api; import cn.iocoder.mall.product.api.bo.*; import cn.iocoder.mall.product.api.dto.ProductSpuAddDTO; import cn.iocoder.mall.product.api.dto.ProductSpuPageDTO; +import cn.iocoder.mall.product.api.dto.ProductSpuSearchListDTO; import cn.iocoder.mall.product.api.dto.ProductSpuUpdateDTO; import java.util.Collection; @@ -23,6 +24,8 @@ public interface ProductSpuService { ProductSpuPageBO getProductSpuPage(ProductSpuPageDTO productSpuPageDTO); + List getProductSpuSearchList(ProductSpuSearchListDTO productSpuSearchListDTO); + List getProductSpuList(Collection ids); ProductSkuBO getProductSku(Integer id); diff --git a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSpuSearchListDTO.java b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSpuSearchListDTO.java new file mode 100644 index 000000000..c5232dd8c --- /dev/null +++ b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSpuSearchListDTO.java @@ -0,0 +1,20 @@ +package cn.iocoder.mall.product.api.dto; + +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 商品 Spu 搜索列表 DTO + */ +@Data +@Accessors(chain = true) +public class ProductSpuSearchListDTO { + + /** + * 商品名 + * + * 模糊匹配 + */ + private String name; + +} diff --git a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductAttrServiceImpl.java b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductAttrServiceImpl.java index 7aee46afe..a48375409 100644 --- a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductAttrServiceImpl.java +++ b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductAttrServiceImpl.java @@ -27,7 +27,7 @@ import java.util.stream.Collectors; * @see cn.iocoder.mall.product.dataobject.ProductAttrValueDO */ @Service -@org.apache.dubbo.config.annotation.Service(validation = "true") +@org.apache.dubbo.config.annotation.Service(validation = "true", version = "${dubbo.provider.ProductAttrService.version}") public class ProductAttrServiceImpl implements ProductAttrService { @Autowired diff --git a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductCategoryServiceImpl.java b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductCategoryServiceImpl.java index e2ebaba6d..c067eefdd 100644 --- a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductCategoryServiceImpl.java +++ b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductCategoryServiceImpl.java @@ -19,7 +19,7 @@ import java.util.Date; import java.util.List; @Service // 实际上不用添加。添加的原因是,必须 Spring 报错提示 -@org.apache.dubbo.config.annotation.Service(validation = "true") +@org.apache.dubbo.config.annotation.Service(validation = "true", version = "${dubbo.provider.ProductCategoryService.version}") public class ProductCategoryServiceImpl implements ProductCategoryService { @Autowired diff --git a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductSpuServiceImpl.java b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductSpuServiceImpl.java index f26380892..decedd4fe 100644 --- a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductSpuServiceImpl.java +++ b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductSpuServiceImpl.java @@ -9,10 +9,7 @@ import cn.iocoder.mall.product.api.bo.*; import cn.iocoder.mall.product.api.constant.ProductCategoryConstants; import cn.iocoder.mall.product.api.constant.ProductErrorCodeEnum; import cn.iocoder.mall.product.api.constant.ProductSpuConstants; -import cn.iocoder.mall.product.api.dto.ProductSkuAddOrUpdateDTO; -import cn.iocoder.mall.product.api.dto.ProductSpuAddDTO; -import cn.iocoder.mall.product.api.dto.ProductSpuPageDTO; -import cn.iocoder.mall.product.api.dto.ProductSpuUpdateDTO; +import cn.iocoder.mall.product.api.dto.*; import cn.iocoder.mall.product.api.message.ProductUpdateMessage; import cn.iocoder.mall.product.convert.ProductSpuConvert; import cn.iocoder.mall.product.dao.ProductSkuMapper; @@ -31,7 +28,7 @@ import java.util.*; import java.util.stream.Collectors; @Service // 实际上不用添加。添加的原因是,必须 Spring 报错提示 -@org.apache.dubbo.config.annotation.Service(validation = "true", version = "1.0.0") +@org.apache.dubbo.config.annotation.Service(validation = "true", version = "${dubbo.provider.ProductSpuService.version}") public class ProductSpuServiceImpl implements ProductSpuService { @Autowired @@ -237,6 +234,14 @@ public class ProductSpuServiceImpl implements ProductSpuService { return productSpuPage; } + @Override + public List getProductSpuSearchList(ProductSpuSearchListDTO productSpuSearchListDTO) { + return ProductSpuConvert.INSTANCE.convert( + productSpuMapper.selectListByNameLikeOrderBySortAsc(productSpuSearchListDTO.getName(), null, null, + null, null, null) + ); + } + @Override public List getProductSpuList(Collection ids) { List spus = productSpuMapper.selectByIds(ids); diff --git a/product/product-service-impl/src/main/resources/config/application.yaml b/product/product-service-impl/src/main/resources/config/application.yaml index 839958124..09cf91221 100644 --- a/product/product-service-impl/src/main/resources/config/application.yaml +++ b/product/product-service-impl/src/main/resources/config/application.yaml @@ -23,7 +23,13 @@ dubbo: name: dubbo scan: base-packages: cn.iocoder.mall.product.service - + provider: + ProductAttrService: + version: 1.0.0 + ProductCategoryService: + version: 1.0.0 + ProductSpuService: + version: 1.0.0 # rocketmq rocketmq: diff --git a/product/product-service-impl/src/main/resources/mapper/ProductSpuMapper.xml b/product/product-service-impl/src/main/resources/mapper/ProductSpuMapper.xml index 2632f011b..2cc42f204 100644 --- a/product/product-service-impl/src/main/resources/mapper/ProductSpuMapper.xml +++ b/product/product-service-impl/src/main/resources/mapper/ProductSpuMapper.xml @@ -113,7 +113,9 @@ AND deleted = 0 ORDER BY sort ASC - LIMIT #{offset}, #{limit} + + LIMIT #{offset}, #{limit} +