소스 검색

商品与地址

plf 4 년 전
부모
커밋
e96358b5c7
31개의 변경된 파일2520개의 추가작업 그리고 17개의 파일을 삭제
  1. 51 0
      src/main/java/com/caimei/config/SwaggerConfig.java
  2. 95 0
      src/main/java/com/caimei/controller/AddressApi.java
  3. 60 0
      src/main/java/com/caimei/controller/HeHeApi.java
  4. 67 0
      src/main/java/com/caimei/controller/ProductApi.java
  5. 85 0
      src/main/java/com/caimei/mapper/AddressMapper.java
  6. 140 0
      src/main/java/com/caimei/mapper/ProductMapper.java
  7. 85 0
      src/main/java/com/caimei/model/ResponseJson.java
  8. 52 0
      src/main/java/com/caimei/model/dto/HeHeUserDto.java
  9. 49 0
      src/main/java/com/caimei/model/po/ProductDetailInfoPo.java
  10. 38 0
      src/main/java/com/caimei/model/po/UserSearchHistoryPo.java
  11. 25 0
      src/main/java/com/caimei/model/vo/ActivityLadderVo.java
  12. 93 0
      src/main/java/com/caimei/model/vo/AddressVo.java
  13. 32 0
      src/main/java/com/caimei/model/vo/CityVo.java
  14. 81 0
      src/main/java/com/caimei/model/vo/ProductDetailsVo.java
  15. 61 0
      src/main/java/com/caimei/model/vo/ProductVo.java
  16. 27 0
      src/main/java/com/caimei/model/vo/ProvinceVo.java
  17. 24 0
      src/main/java/com/caimei/model/vo/RelatedParametersVo.java
  18. 21 0
      src/main/java/com/caimei/model/vo/TownVo.java
  19. 58 0
      src/main/java/com/caimei/service/AddressService.java
  20. 49 0
      src/main/java/com/caimei/service/ProductService.java
  21. 85 0
      src/main/java/com/caimei/service/impl/AddressServiceImpl.java
  22. 162 0
      src/main/java/com/caimei/service/impl/ProductServiceImpl.java
  23. 239 0
      src/main/java/com/caimei/util/HttpRequest.java
  24. 366 0
      src/main/java/com/caimei/util/MathUtil.java
  25. 133 0
      src/main/java/com/caimei/util/ProductUtils.java
  26. 18 3
      src/main/resources/backup.sql
  27. 5 5
      src/main/resources/config/beta/application-beta.yml
  28. 5 5
      src/main/resources/config/dev/application-dev.yml
  29. 4 4
      src/main/resources/config/prod/application-prod.yml
  30. 114 0
      src/main/resources/mapper/AddressMapper.xml
  31. 196 0
      src/main/resources/mapper/ProductMapper.xml

+ 51 - 0
src/main/java/com/caimei/config/SwaggerConfig.java

@@ -0,0 +1,51 @@
+package com.caimei.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.oas.annotations.EnableOpenApi;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+
+/**
+ * `@EnableOpenApi`: 用于开启Swagger的自动配置
+ *
+ * @author Aslee
+ * @date 2021/3/10
+ */
+@EnableOpenApi
+@Configuration
+public class SwaggerConfig {
+    @Value(value = "${swagger.enabled}")
+    Boolean swaggerEnabled;
+
+    @Bean
+    public Docket createRestApi() {
+        return new Docket(DocumentationType.SWAGGER_2)
+                .apiInfo(apiInfo())
+                // 是否开启swagger
+                .enable(swaggerEnabled)
+                .select()
+                // 扫描api
+                .apis(RequestHandlerSelectors.basePackage("com.caimei.controller"))
+                .paths(PathSelectors.any())
+                .build();
+    }
+
+    private ApiInfo apiInfo() {
+        return new ApiInfoBuilder().
+                // 标题
+                        title("呵呵商城小程序spi")
+                // 描述
+                .description("呵呵商城小程序spi")
+                // 服务地址
+                .termsOfServiceUrl("https://mall2c.caimei365.com")
+                // 版本号
+                .version("1.0.0")
+                .build();
+    }
+}

+ 95 - 0
src/main/java/com/caimei/controller/AddressApi.java

@@ -0,0 +1,95 @@
+package com.caimei.controller;
+
+import com.caimei.model.ResponseJson;
+import com.caimei.model.vo.AddressVo;
+import com.caimei.model.vo.ProvinceVo;
+import com.caimei.service.AddressService;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : plf
+ * @date : 2021/3/25
+ */
+@Api(tags = "地址API")
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/other")
+public class AddressApi {
+    private final AddressService addressService;
+
+    /**
+     * 查询用户所有地址
+     */
+    @ApiOperation("查询用户所有地址")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "userId", required = true, value = "机构用户id"),
+            @ApiImplicitParam(name = "pageNum", required = false, value = "第几页"),
+            @ApiImplicitParam(name = "pageSize", required = false, value = "一页多少条")
+    })
+    @GetMapping("/findAddress")
+    public ResponseJson<PageInfo<AddressVo>> findAddress(Integer userId, @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum, @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
+        if (userId == null) {
+            return ResponseJson.error("参数异常", null);
+        }
+        return addressService.findAddress(userId, pageNum, pageSize);
+    }
+
+    /**
+     * 保存或编辑地址
+     */
+    @ApiOperation("保存或编辑地址")
+    @PostMapping("/saveAddress")
+    public ResponseJson<AddressVo> saveAddress(@RequestBody AddressVo address) {
+        return addressService.saveAddress(address);
+    }
+
+    /**
+     * 删除地址
+     */
+    @ApiOperation("删除地址")
+    @ApiImplicitParam(name = "addressId", value = "地址id", required = true)
+    @GetMapping("/deleteAddress")
+    public ResponseJson<String> deleteAddress(Integer addressId) {
+        if (addressId == null) {
+            return ResponseJson.error("参数异常", null);
+        }
+        return addressService.deleteAddress(addressId);
+    }
+
+    /**
+     * 设为默认地址
+     */
+    @ApiOperation("设为默认地址")
+    @GetMapping("/defaultAddress")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "userId", required = true, value = "机构用户id"),
+            @ApiImplicitParam(name = "addressId", required = true, value = "地址id")
+    })
+    public ResponseJson<String> defaultAddress(Integer userId, Integer addressId) {
+        if (null == userId || null == addressId) {
+            return ResponseJson.error("参数异常", null);
+        }
+        return addressService.defaultAddress(userId, addressId);
+    }
+
+    /**
+     * 地址管理:省市区
+     */
+    @ApiOperation("地址管理:省市区")
+    @GetMapping("/list")
+    public ResponseJson<List<ProvinceVo>> address() {
+        return addressService.address();
+    }
+}
+
+

+ 60 - 0
src/main/java/com/caimei/controller/HeHeApi.java

@@ -0,0 +1,60 @@
+package com.caimei.controller;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.caimei.model.ResponseJson;
+import com.caimei.util.HttpRequest;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+/**
+ * 呵呵商城用户API
+ *
+ * @author : plf
+ * @date : 2021/4/21
+ */
+@Api(tags = "呵呵商城用户API")
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/user/he")
+public class HeHeApi {
+    @Value("${caimei.userUrl}")
+    private String userUrl;
+
+    @ApiOperation("微信授权登录")
+    @GetMapping("/authorization")
+    public ResponseJson<String> authorization(String code) throws Exception {
+        String url = userUrl + "/user/he/authorization?code=" + code;
+        String parameters = HttpRequest.sendGet(url);
+        return getResponseJson(parameters);
+    }
+
+    @ApiOperation("手机号验证码登录")
+    @PostMapping("/mobile/login")
+    public ResponseJson<String> mobileLogin(@RequestBody Map<String, Object> param) throws Exception {
+        String url = userUrl + "/user/he/mobile/login";
+        String parameters = HttpRequest.sendPost(url, param);
+        return getResponseJson(parameters);
+    }
+
+    @ApiOperation("发送手机号验证码")
+    @GetMapping("/send")
+    public ResponseJson<String> sendVerificationCode(String mobile) throws Exception {
+        String url = userUrl + "/user/he/send?mobile=" + mobile;
+        String parameters = HttpRequest.sendGet(url);
+        return getResponseJson(parameters);
+    }
+
+    private ResponseJson<String> getResponseJson(String parameters) {
+        JSONObject object = JSONObject.parseObject(parameters);
+        Integer code = object.getInteger("code");
+        String msg = object.getString("msg");
+        String data = object.getString("data");
+        return ResponseJson.success(code, msg, data);
+    }
+}

+ 67 - 0
src/main/java/com/caimei/controller/ProductApi.java

@@ -0,0 +1,67 @@
+package com.caimei.controller;
+
+import com.caimei.model.ResponseJson;
+import com.caimei.model.vo.ProductVo;
+import com.caimei.service.ProductService;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : plf
+ * @date : 2021/4/22
+ */
+@Api(tags = "商品管理API")
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/product")
+public class ProductApi {
+    private final ProductService productService;
+
+    @ApiOperation("轮播图")
+    @GetMapping("/carousel")
+    public ResponseJson<List<String>> carouselFigure() {
+        return productService.carouselFigure();
+    }
+
+    @ApiOperation("商品列表")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "name", value = "搜索商品名称", required = false),
+            @ApiImplicitParam(name = "userId", value = "用户id", required = false),
+            @ApiImplicitParam(name = "pageNum", value = "第几页", required = false),
+            @ApiImplicitParam(name = "pageSize", value = "一页多少条", required = false)
+    })
+    @GetMapping("/list")
+    public ResponseJson<PageInfo<ProductVo>> productList(String name, Integer userId, @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
+                                                         @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
+        return productService.productList(name, userId, pageNum, pageSize);
+    }
+
+    @ApiOperation("商品详情")
+    @ApiImplicitParam(name = "productId", required = true, value = "商品Id")
+    @GetMapping("/details")
+    public ResponseJson<ProductVo> productDetails(Integer productId) {
+        return productService.productDetails(productId);
+    }
+
+    @ApiOperation("商品搜索历史记录")
+    @ApiImplicitParam(name = "userId", required = true, value = "用户id")
+    @GetMapping("/search/history")
+    public ResponseJson<List<String>> searchHistory(Integer userId) {
+        if (userId == null) {
+            return ResponseJson.error("参数异常", null);
+        }
+        return productService.searchHistory(userId);
+    }
+}

+ 85 - 0
src/main/java/com/caimei/mapper/AddressMapper.java

@@ -0,0 +1,85 @@
+package com.caimei.mapper;
+
+import com.caimei.model.vo.AddressVo;
+import com.caimei.model.vo.CityVo;
+import com.caimei.model.vo.ProvinceVo;
+import com.caimei.model.vo.TownVo;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : plf
+ * @date : 2021/3/25
+ */
+@Mapper
+public interface AddressMapper {
+    /**
+     * 查询所有机构用户地址
+     *
+     * @param userId
+     * @return
+     */
+    List<AddressVo> findAddress(Integer userId);
+
+    /**
+     * 查询默认地址
+     *
+     * @param userId
+     * @return
+     */
+    AddressVo findDefaultAddress(Integer userId);
+
+    /**
+     * 更新机构用户地址
+     *
+     * @param address
+     */
+    void updateAddress(AddressVo address);
+
+    /**
+     * 保存机构用户地址
+     *
+     * @param address
+     */
+    void insertAddress(AddressVo address);
+
+    /**
+     * 删除机构用户地址
+     *
+     * @param addressId
+     */
+    void deleteAddress(Integer addressId);
+
+    /**
+     * 设置为默认地址
+     *
+     * @param addressId
+     */
+    void updateDefaultAddress(Integer addressId);
+
+    /**
+     * 查询县级地址
+     *
+     * @return
+     */
+    List<ProvinceVo> findAllProvince();
+
+    /**
+     * 查询市级地址
+     *
+     * @param provinceId
+     * @return
+     */
+    List<CityVo> findAllCity(Integer provinceId);
+
+    /**
+     * 查询区级地址
+     *
+     * @param cityId
+     * @return
+     */
+    List<TownVo> findAllTown(Integer cityId);
+}

+ 140 - 0
src/main/java/com/caimei/mapper/ProductMapper.java

@@ -0,0 +1,140 @@
+package com.caimei.mapper;
+
+import com.caimei.model.po.ProductDetailInfoPo;
+import com.caimei.model.po.UserSearchHistoryPo;
+import com.caimei.model.vo.ActivityLadderVo;
+import com.caimei.model.vo.ProductDetailsVo;
+import com.caimei.model.vo.ProductVo;
+import com.caimei.model.vo.RelatedParametersVo;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : plf
+ * @date : 2021/4/22
+ */
+@Mapper
+public interface ProductMapper {
+    /**
+     * 查询所有的轮播图
+     *
+     * @return
+     */
+    List<String> findImageAll();
+
+    /**
+     * 查询所有商品
+     *
+     * @param name
+     * @return
+     */
+    List<ProductVo> findProductList(String name);
+
+    /**
+     * 查询进行中的活动
+     *
+     * @param productId
+     * @return
+     */
+    Integer findActivityByProductId(Integer productId);
+
+    /**
+     * 活动阶梯价格
+     *
+     * @param activityId 活动id
+     * @param productId  商品id
+     * @return
+     */
+    List<ActivityLadderVo> findActivityLadder(@Param("activityId") Integer activityId, @Param("productId") Integer productId);
+
+    /**
+     * 查询商品详情
+     *
+     * @param productId
+     * @return
+     */
+    ProductDetailsVo findProductByProductId(Integer productId);
+
+    /**
+     * 查询所有的商品图片
+     *
+     * @param productId
+     * @return
+     */
+    List<String> findProductImages(Integer productId);
+
+    /**
+     * 查询详情信息
+     *
+     * @param productId
+     * @return
+     */
+    ProductDetailInfoPo findProductDetail(Integer productId);
+
+    /**
+     * 查询分类名称
+     *
+     * @param bigTypeId
+     * @param smallTypeId
+     * @param tinyTypeId
+     * @return
+     */
+    String findTypeName(@Param("bigTypeId") Integer bigTypeId, @Param("smallTypeId") Integer smallTypeId, @Param("tinyTypeId") Integer tinyTypeId);
+
+    /**
+     * 查询品牌名称
+     *
+     * @param brandId
+     * @return
+     */
+    String findBrandName(Integer brandId);
+
+    /**
+     * 查询相关参数
+     *
+     * @param productId
+     * @return
+     */
+    List<RelatedParametersVo> findParameters(Integer productId);
+
+    /**
+     * 查询历史记录
+     *
+     * @param name 搜索关键词
+     * @return
+     */
+    Integer findSearchHistory(String name);
+
+    /**
+     * 修改关键词时间
+     *
+     * @param recordId
+     */
+    void updateHistoryByDate(Integer recordId);
+
+    /**
+     * 保存搜索历史记录
+     *
+     * @param history
+     */
+    void insertSearchHistory(UserSearchHistoryPo history);
+
+    /**
+     * 查询搜索历史记录
+     *
+     * @param userId
+     * @return
+     */
+    List<String> searchHistory(Integer userId);
+
+    /**
+     * 删除多余的历史记录
+     *
+     * @param userId
+     */
+    void deleteHistoryByUserId(Integer userId);
+}

+ 85 - 0
src/main/java/com/caimei/model/ResponseJson.java

@@ -0,0 +1,85 @@
+package com.caimei.model;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 全局API返回值
+ *
+ * @author : Charles
+ * @date : 2021/3/4
+ */
+@Data
+public class ResponseJson<T> implements Serializable {
+    /** 状态码 */
+    @ApiModelProperty("状态码")
+    private int code;
+    /** 提示信息 */
+    @ApiModelProperty("提示信息")
+    private String msg;
+    /** 返回的数据 */
+    @ApiModelProperty("响应数据")
+    private T data;
+
+    private ResponseJson() {}
+
+    private ResponseJson(int code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    private ResponseJson(int code, String msg, T data) {
+        this.code = code;
+        this.msg = msg;
+        this.data = data;
+    }
+
+    public static ResponseJson success() {
+        return new ResponseJson<>(0, "操作成功");
+    }
+
+    public static<T> ResponseJson<T> success(T data) {
+        return new ResponseJson<>(0, "操作成功", data);
+    }
+
+    public static<T> ResponseJson<T> success(String msg, T data) {
+        return new ResponseJson<>(0, msg, data);
+    }
+
+    public static<T> ResponseJson<T> success(int code, String msg, T data) {
+        return new ResponseJson<>(code, msg, data);
+    }
+
+    public static ResponseJson error() {
+        return new ResponseJson<>(-1, "操作失败");
+    }
+
+    public static ResponseJson error(String msg) {
+        return new ResponseJson<>(-1, msg);
+    }
+
+    public static ResponseJson error(int code, String msg) {
+        return new ResponseJson<>(code, msg);
+    }
+
+    public static<T> ResponseJson<T> error(T data) {
+        return new ResponseJson<>(-1, "操作失败", data);
+    }
+
+    public static<T> ResponseJson<T> error(String msg, T data) {
+        return new ResponseJson<>(-1, msg, data);
+    }
+
+    public static<T> ResponseJson<T> error(int code, String msg, T data) {
+        return new ResponseJson<>(code, msg, data);
+    }
+
+    @Override
+    public String toString() {
+        return "JsonModel{" + "code=" + code + ", msg='" + msg + '\'' + ", data=" + data + '}';
+    }
+
+    private static final long serialVersionUID = 1L;
+}

+ 52 - 0
src/main/java/com/caimei/model/dto/HeHeUserDto.java

@@ -0,0 +1,52 @@
+package com.caimei.model.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * Description
+ *
+ * @author : plf
+ * @date : 2021/4/22
+ */
+@ApiModel("呵呵小程序登录")
+@Data
+public class HeHeUserDto {
+    /**
+     * 手机号
+     */
+    @NotNull
+    @ApiModelProperty("手机号")
+    private String mobile;
+
+    /**
+     * 验证码
+     */
+    @NotNull
+    @ApiModelProperty("验证码")
+    private String verificationCode;
+
+    /**
+     * 微信昵称
+     */
+    @NotNull
+    @ApiModelProperty("微信昵称")
+    private String nickName;
+
+    /**
+     * 微信头像
+     */
+    @NotNull
+    @ApiModelProperty("微信头像")
+    private String headImgUrl;
+
+    /**
+     * 微信openid
+     */
+    @NotNull
+    @ApiModelProperty("微信openid")
+    private String openId;
+}

+ 49 - 0
src/main/java/com/caimei/model/po/ProductDetailInfoPo.java

@@ -0,0 +1,49 @@
+package com.caimei.model.po;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * productdetailinfo
+ *
+ * @author
+ */
+@Data
+public class ProductDetailInfoPo implements Serializable {
+    private Integer productDetailInfoId;
+
+    /**
+     * 商品Id
+     */
+    private Integer productId;
+
+    private String propValueAlias;
+
+    private String propValueImages;
+
+    /**
+     * 商品详情信息
+     */
+    private String detailInfo;
+
+    private String detailInfoTxt;
+
+    private String seoTitle;
+
+    private String seoKeyword;
+
+    private String seoDes;
+
+    /**
+     * 服务详情
+     */
+    private String serviceInfo;
+
+    /**
+     * 订购方案
+     */
+    private String orderInfo;
+
+    private static final long serialVersionUID = 1L;
+}

+ 38 - 0
src/main/java/com/caimei/model/po/UserSearchHistoryPo.java

@@ -0,0 +1,38 @@
+package com.caimei.model.po;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * user_search_history
+ *
+ * @author
+ */
+@Data
+public class UserSearchHistoryPo implements Serializable {
+    private Long id;
+
+    /**
+     * 用户ID
+     */
+    private Long userId;
+
+    /**
+     * 搜索关键词
+     */
+    private String searchWord;
+
+    /**
+     * 搜索时间
+     */
+    private Date searchDate;
+
+    /**
+     * 删除标记 0 否,其余是
+     */
+    private String delFlag;
+
+    private static final long serialVersionUID = 1L;
+}

+ 25 - 0
src/main/java/com/caimei/model/vo/ActivityLadderVo.java

@@ -0,0 +1,25 @@
+package com.caimei.model.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * Description
+ *
+ * @author : plf
+ * @date : 2021/4/23
+ */
+@Data
+public class ActivityLadderVo {
+    /**
+     * 购买数量
+     */
+    private Integer buyNum;
+
+    /**
+     * 购买价格
+     */
+    private BigDecimal buyPrice;
+
+}

+ 93 - 0
src/main/java/com/caimei/model/vo/AddressVo.java

@@ -0,0 +1,93 @@
+package com.caimei.model.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * address
+ *
+ * @author
+ */
+@Data
+public class AddressVo implements Serializable {
+    /**
+     * 用户地址ID
+     */
+    @ApiModelProperty("用户地址ID")
+    private Integer addressId;
+
+    /**
+     * 用户ID
+     */
+    @ApiModelProperty("用户ID")
+    private Integer userId;
+
+    /**
+     * 收货人
+     */
+    @ApiModelProperty("收货人")
+    private String shouHuoRen;
+
+    /**
+     * 区ID
+     */
+    @ApiModelProperty("区ID")
+    private Integer townId;
+
+    /**
+     * 地址
+     */
+    @ApiModelProperty("地址")
+    private String address;
+
+    /**
+     * 邮编
+     */
+    private String postalCode;
+
+    /**
+     * 电话
+     */
+    private String phone;
+
+    /**
+     * 手机
+     */
+    @ApiModelProperty("手机")
+    private String mobile;
+
+    /**
+     * 是否默认收货地址(0 不是默认,1 默认)
+     */
+    @ApiModelProperty("是否默认收货地址(0 不是默认,1 默认)")
+    private String defaultFlag;
+
+    /**
+     * 市id
+     */
+    private Integer cityId;
+
+    /**
+     * 县id
+     */
+    private Integer provinceId;
+
+    /**
+     * 区名称
+     */
+    private String townName;
+
+    /**
+     * 市名称
+     */
+    private String cityName;
+
+    /**
+     * 县名称
+     */
+    private String provinceName;
+
+    private static final long serialVersionUID = 1L;
+}

+ 32 - 0
src/main/java/com/caimei/model/vo/CityVo.java

@@ -0,0 +1,32 @@
+package com.caimei.model.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : plf
+ * @date : 2021/3/25
+ */
+@Data
+public class CityVo implements Serializable {
+    private Integer cityId;
+
+    /**
+     * 所属省ID
+     */
+    private Integer provinceId;
+
+    /**
+     * 名称
+     */
+    private String name;
+
+    /**
+     * 区级地址
+     */
+    private List<TownVo> townList;
+}

+ 81 - 0
src/main/java/com/caimei/model/vo/ProductDetailsVo.java

@@ -0,0 +1,81 @@
+package com.caimei.model.vo;
+
+import com.caimei.model.po.ProductDetailInfoPo;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : plf
+ * @date : 2021/4/23
+ */
+@Data
+public class ProductDetailsVo extends ProductVo {
+    /**
+     * 品牌id
+     */
+    private Integer brandId;
+
+    /**
+     * 一级分类ID
+     */
+    private Integer bigTypeId;
+
+    /**
+     * 二级分类ID
+     */
+    private Integer smallTypeId;
+
+    /**
+     * 三级分类Id
+     */
+    private Integer tinyTypeId;
+
+    /**
+     * 包装规格
+     */
+    private String unit;
+
+    /**
+     * 商品标签用英文逗号隔开,中文逗号或其它一律不作切割
+     */
+    private String tags;
+
+    /**
+     * 所在分类名称
+     */
+    private String typeName;
+
+    /**
+     * 品牌名称
+     */
+    private String brandName;
+
+    /**
+     * 标签数组
+     */
+    private String[] tagsList;
+
+    /**
+     * 所有商品图片
+     */
+    private List<String> imageList;
+
+    /**
+     * 商品详情
+     */
+    private ProductDetailInfoPo productDetail;
+
+    /**
+     * 相关参数
+     */
+    private List<RelatedParametersVo> parametersList;
+
+    /**
+     * 活动阶梯
+     */
+    List<ActivityLadderVo> ladderList;
+
+}

+ 61 - 0
src/main/java/com/caimei/model/vo/ProductVo.java

@@ -0,0 +1,61 @@
+package com.caimei.model.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : plf
+ * @date : 2021/4/22
+ */
+@Data
+public class ProductVo implements Serializable {
+    /**
+     * 对应采美商品id
+     */
+    private Integer productId;
+
+    /**
+     * 是否为推荐商品(0 没推荐,1 推荐商品)
+     */
+    private String recommend;
+
+    /**
+     * 售价
+     */
+    private BigDecimal price;
+
+    /**
+     * 商品名称
+     */
+    private String name;
+
+    /**
+     * 商品图片
+     */
+    private String mainImage;
+
+    /**
+     * 活动状态:0没有活动,1活动价
+     */
+    private Integer activeStatus = 0;
+
+    /**
+     * 是否含税 0不含税,1含税
+     */
+    private String includedTax;
+
+    /**
+     * 发票类型(基于是否含税基础) 1增值税专用发票,2增值税普通发票, 3不能开票
+     */
+    private String invoiceType;
+
+    /**
+     * 机构税率 :增值税默认13%,普通票6%取值范围[0-100]
+     */
+    private BigDecimal clubTaxPoint;
+}

+ 27 - 0
src/main/java/com/caimei/model/vo/ProvinceVo.java

@@ -0,0 +1,27 @@
+package com.caimei.model.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : plf
+ * @date : 2021/3/25
+ */
+@Data
+public class ProvinceVo implements Serializable {
+    private Integer provinceId;
+
+    /**
+     * 名称
+     */
+    private String name;
+
+    /**
+     * 市级地址
+     */
+    private List<CityVo> cityList;
+}

+ 24 - 0
src/main/java/com/caimei/model/vo/RelatedParametersVo.java

@@ -0,0 +1,24 @@
+package com.caimei.model.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * Description
+ *
+ * @author : plf
+ * @date : 2021/4/23
+ */
+@Data
+public class RelatedParametersVo implements Serializable {
+    /**
+     * 参数名称
+     */
+    private String paramsName;
+
+    /**
+     * 参数内容
+     */
+    private String paramsContent;
+}

+ 21 - 0
src/main/java/com/caimei/model/vo/TownVo.java

@@ -0,0 +1,21 @@
+package com.caimei.model.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * Description
+ *
+ * @author : plf
+ * @date : 2021/3/25
+ */
+@Data
+public class TownVo implements Serializable {
+    private Integer townId;
+
+    /**
+     * 名称
+     */
+    private String name;
+}

+ 58 - 0
src/main/java/com/caimei/service/AddressService.java

@@ -0,0 +1,58 @@
+package com.caimei.service;
+
+import com.caimei.model.ResponseJson;
+import com.caimei.model.vo.AddressVo;
+import com.caimei.model.vo.ProvinceVo;
+import com.github.pagehelper.PageInfo;
+
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : plf
+ * @date : 2021/3/25
+ */
+public interface AddressService {
+    /**
+     * 查询用户所有地址
+     *
+     * @param userId
+     * @param pageNum
+     * @param pageSize
+     * @return
+     */
+    ResponseJson<PageInfo<AddressVo>> findAddress(Integer userId, Integer pageNum, Integer pageSize);
+
+    /**
+     * 保存或编辑地址
+     *
+     * @param address
+     * @return
+     */
+    ResponseJson<AddressVo> saveAddress(AddressVo address);
+
+    /**
+     * 删除地址
+     *
+     * @param addressId
+     * @return
+     */
+    ResponseJson<String> deleteAddress(Integer addressId);
+
+    /**
+     * 设为默认地址
+     *
+     * @param userId
+     * @param addressId
+     * @return
+     */
+    ResponseJson<String> defaultAddress(Integer userId, Integer addressId);
+
+    /**
+     * 地址列表数据
+     *
+     * @return
+     */
+    ResponseJson<List<ProvinceVo>> address();
+}

+ 49 - 0
src/main/java/com/caimei/service/ProductService.java

@@ -0,0 +1,49 @@
+package com.caimei.service;
+
+import com.caimei.model.ResponseJson;
+import com.caimei.model.vo.ProductVo;
+import com.github.pagehelper.PageInfo;
+
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : plf
+ * @date : 2021/4/22
+ */
+public interface ProductService {
+    /**
+     * 轮播图
+     *
+     * @return
+     */
+    ResponseJson<List<String>> carouselFigure();
+
+    /**
+     * 商品列表
+     *
+     * @param name     商品名称
+     * @param userId   用户id
+     * @param pageNum
+     * @param pageSize
+     * @return
+     */
+    ResponseJson<PageInfo<ProductVo>> productList(String name, Integer userId, Integer pageNum, Integer pageSize);
+
+    /**
+     * 商品详情
+     *
+     * @param productId 商品id
+     * @return
+     */
+    ResponseJson<ProductVo> productDetails(Integer productId);
+
+    /**
+     * 商品搜索历史记录
+     *
+     * @param userId 用户id
+     * @return
+     */
+    ResponseJson<List<String>> searchHistory(Integer userId);
+}

+ 85 - 0
src/main/java/com/caimei/service/impl/AddressServiceImpl.java

@@ -0,0 +1,85 @@
+package com.caimei.service.impl;
+
+import com.caimei.mapper.AddressMapper;
+import com.caimei.model.ResponseJson;
+import com.caimei.model.vo.AddressVo;
+import com.caimei.model.vo.CityVo;
+import com.caimei.model.vo.ProvinceVo;
+import com.caimei.model.vo.TownVo;
+import com.caimei.service.AddressService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : plf
+ * @date : 2021/3/25
+ */
+@Service
+public class AddressServiceImpl implements AddressService {
+    @Resource
+    private AddressMapper addressMapper;
+
+    @Override
+    public ResponseJson<PageInfo<AddressVo>> findAddress(Integer userId, Integer pageNum, Integer pageSize) {
+        PageHelper.startPage(pageNum, pageSize);
+        List<AddressVo> addressList = addressMapper.findAddress(userId);
+        PageInfo<AddressVo> pageInfo = new PageInfo<>(addressList);
+        return ResponseJson.success(pageInfo);
+    }
+
+    @Override
+    public ResponseJson<AddressVo> saveAddress(AddressVo address) {
+        if (address.getDefaultFlag() != null && "1".equals(address.getDefaultFlag())) {
+            AddressVo addressVo = addressMapper.findDefaultAddress(address.getUserId());
+            if (addressVo != null) {
+                addressVo.setDefaultFlag("0");
+                addressMapper.updateAddress(addressVo);
+            }
+        }
+        if (address.getAddressId() == null) {
+            addressMapper.insertAddress(address);
+        } else {
+            addressMapper.updateAddress(address);
+        }
+        return ResponseJson.success(address);
+    }
+
+    @Override
+    public ResponseJson<String> deleteAddress(Integer addressId) {
+        addressMapper.deleteAddress(addressId);
+        return ResponseJson.success("删除成功");
+    }
+
+    @Override
+    public ResponseJson<String> defaultAddress(Integer userId, Integer addressId) {
+        AddressVo address = addressMapper.findDefaultAddress(userId);
+        if (null != address) {
+            address.setDefaultFlag("0");
+            addressMapper.updateAddress(address);
+        }
+        addressMapper.updateDefaultAddress(addressId);
+        return ResponseJson.success("操作成功");
+    }
+
+    @Override
+    public ResponseJson<List<ProvinceVo>> address() {
+        List<ProvinceVo> list = addressMapper.findAllProvince();
+        for (ProvinceVo province : list) {
+            List<CityVo> cityList = addressMapper.findAllCity(province.getProvinceId());
+            province.setCityList(cityList);
+            if (cityList != null && cityList.size() > 0) {
+                for (CityVo city : cityList) {
+                    List<TownVo> townList = addressMapper.findAllTown(city.getCityId());
+                    city.setTownList(townList);
+                }
+            }
+        }
+        return ResponseJson.success(list);
+    }
+}

+ 162 - 0
src/main/java/com/caimei/service/impl/ProductServiceImpl.java

@@ -0,0 +1,162 @@
+package com.caimei.service.impl;
+
+import com.caimei.mapper.ProductMapper;
+import com.caimei.model.ResponseJson;
+import com.caimei.model.po.ProductDetailInfoPo;
+import com.caimei.model.po.UserSearchHistoryPo;
+import com.caimei.model.vo.ActivityLadderVo;
+import com.caimei.model.vo.ProductDetailsVo;
+import com.caimei.model.vo.ProductVo;
+import com.caimei.model.vo.RelatedParametersVo;
+import com.caimei.service.ProductService;
+import com.caimei.util.MathUtil;
+import com.caimei.util.ProductUtils;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : plf
+ * @date : 2021/4/22
+ */
+@Service
+public class ProductServiceImpl implements ProductService {
+    @Resource
+    private ProductMapper productMapper;
+    @Value("${caimei.oldapi}")
+    private String domain;
+
+    @Override
+    public ResponseJson<List<String>> carouselFigure() {
+        List<String> images = productMapper.findImageAll();
+        return ResponseJson.success(images);
+    }
+
+    @Override
+    public ResponseJson<PageInfo<ProductVo>> productList(String name, Integer userId, Integer pageNum, Integer pageSize) {
+        PageHelper.startPage(pageNum, pageSize);
+        List<ProductVo> productList = productMapper.findProductList(name);
+        productList.forEach((product) -> {
+            product.setMainImage(ProductUtils.getImageURL("product", product.getMainImage(), 0, domain));
+            Integer activityId = productMapper.findActivityByProductId(product.getProductId());
+            if (activityId != null && activityId > 0) {
+                product.setActiveStatus(1);
+                //活动阶梯
+                List<ActivityLadderVo> ladderList = productMapper.findActivityLadder(activityId, product.getProductId());
+                if (ladderList != null && ladderList.size() > 0) {
+                    product.setPrice(ladderList.get(0).getBuyPrice());
+                }
+            }
+            //税费
+            boolean addTaxFlag = ("0".equals(product.getIncludedTax()) && ("1".equals(product.getInvoiceType()) || "2".equals(product.getInvoiceType())));
+            if (addTaxFlag) {
+                BigDecimal addedValueTax = MathUtil.div(MathUtil.mul(product.getPrice(), product.getClubTaxPoint()), BigDecimal.valueOf(100));
+                BigDecimal price = MathUtil.add(product.getPrice(), addedValueTax);
+                product.setPrice(price);
+            }
+        });
+        PageInfo<ProductVo> pageInfo = new PageInfo<>(productList);
+
+        //搜索关键字
+        if (StringUtils.isNotBlank(name) && userId != null) {
+            Integer recordId = productMapper.findSearchHistory(name);
+            if (recordId != null && recordId > 0) {
+                productMapper.updateHistoryByDate(recordId);
+            } else {
+                UserSearchHistoryPo history = new UserSearchHistoryPo();
+                history.setUserId(Long.valueOf(userId));
+                history.setDelFlag("0");
+                history.setSearchWord(name);
+                history.setSearchDate(new Date());
+                productMapper.insertSearchHistory(history);
+            }
+        }
+        return ResponseJson.success(pageInfo);
+    }
+
+    @Override
+    public ResponseJson<ProductVo> productDetails(Integer productId) {
+        ProductDetailsVo product = productMapper.findProductByProductId(productId);
+        if (product == null) {
+            //商品不存在
+            return ResponseJson.error("商品不存在", null);
+        }
+        String[] split = null;
+        //商品标签
+        if (product.getTags() != null) {
+            String tags = product.getTags();
+            tags = tags.replace(" ", ",").replace("、", ",").replace(",", ",");
+            split = tags.split(",");
+            List<String> list = new ArrayList<>();
+            for (String s : split) {
+                if (StringUtils.isNotBlank(s)) {
+                    list.add(s);
+                }
+            }
+            split = list.toArray(new String[list.size()]);
+        }
+        product.setTagsList(split);
+        product.setMainImage(ProductUtils.getImageURL("product", product.getMainImage(), 0, domain));
+        //商品图片
+        List<String> list = new ArrayList<>();
+        List<String> imageList = productMapper.findProductImages(product.getProductId());
+        for (String image : imageList) {
+            image = ProductUtils.getImageURL("product", image, 0, domain);
+            list.add(image);
+        }
+        product.setImageList(list);
+        //商品详情
+        ProductDetailInfoPo productDetail = productMapper.findProductDetail(product.getProductId());
+        product.setProductDetail(productDetail);
+        //商品分类
+        String typeName = productMapper.findTypeName(product.getBigTypeId(), product.getSmallTypeId(), product.getTinyTypeId());
+        product.setTypeName(typeName);
+        //品牌名称
+        String brandName = productMapper.findBrandName(product.getBrandId());
+        if (StringUtils.isNotBlank(brandName)) {
+            product.setBrandName(brandName);
+        }
+        //相关参数
+        List<RelatedParametersVo> parametersList = productMapper.findParameters(product.getProductId());
+        product.setParametersList(parametersList);
+
+        Integer activityId = productMapper.findActivityByProductId(product.getProductId());
+        if (activityId != null && activityId > 0) {
+            product.setActiveStatus(1);
+            //活动阶梯
+            List<ActivityLadderVo> ladderList = productMapper.findActivityLadder(activityId, product.getProductId());
+            if (ladderList != null && ladderList.size() > 0) {
+                product.setPrice(ladderList.get(0).getBuyPrice());
+            }
+            product.setLadderList(ladderList);
+        }
+        //税费
+        boolean addTaxFlag = ("0".equals(product.getIncludedTax()) && ("1".equals(product.getInvoiceType()) || "2".equals(product.getInvoiceType())));
+        if (addTaxFlag) {
+            BigDecimal addedValueTax = MathUtil.div(MathUtil.mul(product.getPrice(), product.getClubTaxPoint()), BigDecimal.valueOf(100));
+            BigDecimal price = MathUtil.add(product.getPrice(), addedValueTax);
+            product.setPrice(price);
+        }
+        return ResponseJson.success(product);
+    }
+
+    @Override
+    public ResponseJson<List<String>> searchHistory(Integer userId) {
+        List<String> searchList = productMapper.searchHistory(userId);
+        if (searchList.size() == 10) {
+            //只保留10条记录
+            productMapper.deleteHistoryByUserId(userId);
+        }
+        return ResponseJson.success(searchList);
+    }
+}

+ 239 - 0
src/main/java/com/caimei/util/HttpRequest.java

@@ -0,0 +1,239 @@
+package com.caimei.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * HTTP 请求工具
+ */
+public class HttpRequest {
+    /**
+     * 向指定URL发送GET方法的请求
+     *
+     * @param url   发送请求的URL
+     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
+     * @return URL 所代表远程资源的响应结果
+     * @throws Exception
+     */
+    @SuppressWarnings("unused")
+    public static String sendGetWithParameter(String url, String param) throws Exception {
+        StringBuffer result = new StringBuffer();
+        BufferedReader in = null;
+        try {
+            String urlNameString = url + "?" + param;
+            URL realUrl = new URL(urlNameString);
+            // 打开和URL之间的连接
+            URLConnection connection = realUrl.openConnection();
+            // 设置通用的请求属性
+            connection.setRequestProperty("accept", "*/*");
+            connection.setRequestProperty("connection", "Keep-Alive");
+            connection.setRequestProperty("Accept-Charset", "utf-8");
+            connection.setRequestProperty("contentType", "utf-8");
+            connection.setConnectTimeout(5000);
+            // 建立实际的连接
+            connection.connect();
+            // 获取所有响应头字段
+            Map<String, List<String>> map = connection.getHeaderFields();
+            // 遍历所有的响应头字段
+            for (String key : map.keySet()) {
+                // System.out.println(key + "--->" + map.get(key)); //关闭响应头的输出
+            }
+            // 定义 BufferedReader输入流来读取URL的响应
+            in = new BufferedReader(new InputStreamReader(
+                    connection.getInputStream()));
+            String line;
+            while ((line = in.readLine()) != null) {
+                result.append(line);
+            }
+        } catch (Exception e) {
+            throw e;
+        }
+        // 使用finally块来关闭输入流
+        finally {
+            try {
+                if (in != null) {
+                    in.close();
+                }
+            } catch (Exception e2) {
+                throw e2;
+            }
+        }
+        return result.toString();
+    }
+
+
+    @SuppressWarnings("unused")
+    public static String sendGet(String url) throws Exception {
+        StringBuffer result = new StringBuffer();
+        BufferedReader in = null;
+        try {
+
+            URL realUrl = new URL(url);
+            // 打开和URL之间的连接
+            URLConnection connection = realUrl.openConnection();
+            // 设置通用的请求属性
+            connection.setRequestProperty("accept", "*/*");
+            connection.setRequestProperty("connection", "Keep-Alive");
+            connection.setRequestProperty("Accept-Charset", "utf-8");
+            connection.setRequestProperty("contentType", "utf-8");
+            connection.setConnectTimeout(5000);
+            // 建立实际的连接
+            connection.connect();
+            // 获取所有响应头字段
+            Map<String, List<String>> map = connection.getHeaderFields();
+            // 遍历所有的响应头字段
+            for (String key : map.keySet()) {
+                //  System.out.println(key + "--->" + map.get(key));
+            }
+            // 定义 BufferedReader输入流来读取URL的响应
+            in = new BufferedReader(new InputStreamReader(
+                    connection.getInputStream()));
+            String line;
+            while ((line = in.readLine()) != null) {
+                result.append(line);
+            }
+        } catch (Exception e) {
+            throw e;
+        }
+        // 使用finally块来关闭输入流
+        finally {
+            try {
+                if (in != null) {
+                    in.close();
+                }
+            } catch (Exception e2) {
+                throw e2;
+            }
+        }
+        return result.toString();
+    }
+
+    /**
+     * 向指定 URL 发送POST方法的请求
+     *
+     * @param url   发送请求的 URL
+     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
+     * @return 所代表远程资源的响应结果
+     * @throws Exception
+     */
+    public static String sendPost(String url, String param) throws Exception {
+        PrintWriter out = null;
+        BufferedReader in = null;
+        StringBuffer result = new StringBuffer();
+        try {
+            URL realUrl = new URL(url);
+            // 打开和URL之间的连接
+            URLConnection conn = realUrl.openConnection();
+            // 设置通用的请求属性
+            conn.setRequestProperty("accept", "*/*");
+            conn.setRequestProperty("connection", "Keep-Alive");
+            conn.setRequestProperty("Accept-Charset", "utf-8");
+            conn.setRequestProperty("contentType", "utf-8");
+            conn.setConnectTimeout(5000);
+            // 发送POST请求必须设置如下两行
+            conn.setDoOutput(true);
+            conn.setDoInput(true);
+            // 获取URLConnection对象对应的输出流
+            out = new PrintWriter(conn.getOutputStream());
+            // 发送请求参数
+            out.print(param);
+            // flush输出流的缓冲
+            out.flush();
+            // 定义BufferedReader输入流来读取URL的响应
+            in = new BufferedReader(
+                    new InputStreamReader(conn.getInputStream()));
+            String line;
+            while ((line = in.readLine()) != null) {
+                result.append(line);
+            }
+        } catch (Exception e) {
+            throw e;
+        }
+        //使用finally块来关闭输出流、输入流
+        finally {
+            try {
+                if (out != null) {
+                    out.close();
+                }
+                if (in != null) {
+                    in.close();
+                }
+            } catch (Exception ex) {
+                throw ex;
+            }
+        }
+        return result.toString();
+    }
+
+
+    /**
+     * 向指定 URL 发送POST方法的请求
+     *
+     * @param url      发送请求的 URL
+     * @param paramMap 请求参数
+     * @return 所代表远程资源的响应结果
+     */
+    public static String sendPost(String url, Map<String, ?> paramMap) throws Exception {
+        PrintWriter out = null;
+        BufferedReader in = null;
+        String result = "";
+
+        String param = "";
+        Iterator<String> it = paramMap.keySet().iterator();
+
+        while (it.hasNext()) {
+            String key = it.next();
+            param += key + "=" + paramMap.get(key) + "&";
+        }
+
+        try {
+            URL realUrl = new URL(url);
+            // 打开和URL之间的连接
+            URLConnection conn = realUrl.openConnection();
+            // 设置通用的请求属性
+            conn.setRequestProperty("accept", "*/*");
+            conn.setRequestProperty("connection", "Keep-Alive");
+            conn.setRequestProperty("Accept-Charset", "utf-8");
+            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
+            // 发送POST请求必须设置如下两行
+            conn.setDoOutput(true);
+            conn.setDoInput(true);
+            // 获取URLConnection对象对应的输出流
+            out = new PrintWriter(conn.getOutputStream());
+            // 发送请求参数
+            out.print(param);
+            // flush输出流的缓冲
+            out.flush();
+            // 定义BufferedReader输入流来读取URL的响应
+            in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
+            String line;
+            while ((line = in.readLine()) != null) {
+                result += line;
+            }
+        } catch (Exception e) {
+            throw e;
+        }
+        //使用finally块来关闭输出流、输入流
+        finally {
+            try {
+                if (out != null) {
+                    out.close();
+                }
+                if (in != null) {
+                    in.close();
+                }
+            } catch (IOException ex) {
+                throw ex;
+            }
+        }
+        return result;
+    }
+
+}

+ 366 - 0
src/main/java/com/caimei/util/MathUtil.java

@@ -0,0 +1,366 @@
+package com.caimei.util;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Description
+ *
+ * @author : Charles
+ * @date : 2020/3/19
+ */
+
+public class MathUtil {
+
+
+    public static int default_scale = 4;
+
+    private static final int MAX_GENERATE_COUNT = 99999;
+    private static int generateCount = 0;
+
+
+    /**
+     * 两个实数相除,默认四舍五入到4位
+     *
+     * @param v1
+     * @param v2
+     * @return
+     */
+    public static BigDecimal div(Object v1, Object v2) {
+        return div(v1, v2, default_scale);
+    }
+
+    /**
+     * 两个实数相除,默认四舍五入到scale位
+     *
+     * @param v1
+     * @param v2
+     * @param scale
+     * @return
+     */
+    public static BigDecimal div(Object v1, Object v2, int scale) {
+        if (scale < 0) {
+            throw new IllegalArgumentException("四舍五入的位数不能为负数");
+        }
+        BigDecimal b1 = convert(v1);
+        BigDecimal b2 = convert(v2);
+        if (equal0(b2)) {
+            throw new IllegalArgumentException("除数不能为0");
+        }
+        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP);
+    }
+
+    public static String formatDouble(double s) {
+        DecimalFormat fmt = new DecimalFormat("0.00");
+        return fmt.format(s);
+    }
+
+    public static String[] intersect(String[] arr1, String[] arr2) {
+        List<String> l = new LinkedList<String>();
+        Set<String> common = new HashSet<String>();
+        for (String str : arr1) {
+            if (!l.contains(str)) {
+                l.add(str);
+            }
+        }
+        for (String str : arr2) {
+            if (l.contains(str)) {
+                common.add(str);
+            }
+        }
+        String[] result = {};
+        return common.toArray(result);
+    }
+
+
+    public static synchronized String getUniqueString() {
+        if (generateCount > 99999) {
+            generateCount = 0;
+        }
+        String uniqueNumber = Long.toString(System.currentTimeMillis())
+                + Integer.toString(generateCount);
+        generateCount++;
+        return uniqueNumber;
+    }
+
+    /**
+     * 构造函数
+     */
+    private MathUtil() {
+
+    }
+
+    /**
+     * 类型转换函数
+     *
+     * @param o
+     * @return
+     */
+    public static BigDecimal convert(Object o) {
+        if (o == null) {
+            return BigDecimal.ZERO;
+        } else if (o instanceof BigDecimal) {
+            return (BigDecimal) o;
+        }
+        String str = o.toString();
+        if (StringUtils.isNotBlank(str)) {
+            return new BigDecimal(str);
+        } else {
+            return BigDecimal.ZERO;
+        }
+    }
+
+    /**
+     * 两个实数相加
+     *
+     * @param v1
+     * @param v2
+     * @return
+     */
+    public static BigDecimal add(Object v1, Object v2) {
+        BigDecimal b1 = convert(v1);
+        BigDecimal b2 = convert(v2);
+        return b1.add(b2);
+
+    }
+
+    /**
+     * 两个实数相减
+     *
+     * @param v1
+     * @param v2
+     * @return
+     */
+    public static BigDecimal sub(Object v1, Object v2) {
+        BigDecimal b1 = convert(v1);
+        BigDecimal b2 = convert(v2);
+        return b1.subtract(b2);
+
+    }
+
+    /**
+     * 两个实数相乘
+     *
+     * @param v1
+     * @param v2
+     * @return
+     */
+    public static BigDecimal mul(Object v1, Object v2) {
+        BigDecimal b1 = convert(v1);
+        BigDecimal b2 = convert(v2);
+        return b1.multiply(b2);
+
+    }
+
+    /**
+     * 相个实数相乘并四舍五入到Sacle位
+     *
+     * @param v1
+     * @param v2
+     * @param scale
+     * @return
+     */
+    public static BigDecimal mul(Object v1, Object v2, int scale) {
+        if (scale < 0) {
+            throw new IllegalArgumentException("四舍五入的位数不能为负数");
+        }
+        BigDecimal b1 = convert(v1);
+        BigDecimal b2 = convert(v2);
+        return b1.multiply(b2).setScale(scale, BigDecimal.ROUND_HALF_UP);
+
+    }
+
+    /**
+     * 两个实数比较
+     *
+     * @param v1
+     * @param v2
+     * @return
+     */
+    public static int compare(Object v1, Object v2) {
+        BigDecimal b1 = convert(v1);
+        BigDecimal b2 = convert(v2);
+        return b1.compareTo(b2);
+    }
+
+    public static boolean equal0(Object v1) {
+        BigDecimal b1 = convert(v1);
+        return b1.compareTo(BigDecimal.ZERO) == 0;
+    }
+
+    public static boolean notEqual0(Object v1) {
+        BigDecimal b1 = convert(v1);
+        return b1.compareTo(BigDecimal.ZERO) != 0;
+    }
+
+    /**
+     * 两个整数比较
+     *
+     * @param v1
+     * @param v2
+     * @return
+     */
+    public static int compareInt(Integer v1, Integer v2) {
+
+        if (v1 == null) {
+            v1 = new Integer(0);
+        }
+        if (v2 == null) {
+            v2 = new Integer(0);
+        }
+        return v1.compareTo(v2);
+    }
+
+    /**
+     * 判断两个整数是否相等
+     *
+     * @param v1
+     * @param v2
+     * @return
+     */
+    public static boolean equal(Integer v1, Integer v2) {
+
+        int result = compareInt(v1, v2);
+        return result == 0;
+    }
+
+    /**
+     * 判断两个整数不等
+     *
+     * @param v1
+     * @param v2
+     * @return
+     */
+    public static boolean notEqual(Integer v1, Integer v2) {
+        int result = compareInt(v1, v2);
+        return result != 0;
+    }
+
+    /**
+     * 实数的四舍五入函数
+     *
+     * @param v
+     * @param scale
+     * @return
+     */
+    public static BigDecimal round(Object v, int scale) {
+        if (scale < 0) {
+            throw new IllegalArgumentException("四舍五入的位数不能为负数");
+        }
+        BigDecimal b = convert(v);
+        return b.setScale(scale, BigDecimal.ROUND_HALF_UP);
+    }
+
+    /**
+     * 将字符串转换成整型
+     *
+     * @param value
+     * @param defaultNum
+     * @return
+     */
+    public static int parsetInt(String value, int defaultNum) {
+        if (value != null && !value.equals("")) {
+            int num = defaultNum;
+            try {
+                num = Integer.parseInt(value);
+            } catch (Exception ignored) {
+            }
+            return num;
+        } else {
+            return defaultNum;
+        }
+    }
+
+    /**
+     * 将string转换为double
+     *
+     * @param value
+     * @param defaultNum
+     * @return
+     */
+    public static double parseDouble(String value, double defaultNum) {
+        if (StringUtils.isBlank(value)) {
+            return defaultNum;
+        }
+
+        value = value.replaceAll(",", "");
+        value = value.replaceAll(" ", "");
+        value = value.replaceAll("¥", "");
+
+        double num = defaultNum;
+        try {
+            num = Double.parseDouble(value);
+        } catch (Exception ignored) {
+        }
+        return num;
+    }
+
+    /**
+     * 将string 转换为double
+     *
+     * @param value
+     * @return
+     */
+    public static double parseDouble(String value) {
+        return parseDouble(value, 0);
+    }
+
+    public static int isNullInteger(Integer v) {
+        if (v == null) {
+            return 0;
+        } else {
+            return v.intValue();
+        }
+    }
+
+    //
+    private static double EARTH_RADIUS = 6378.137;
+
+    private static double rad(double d) {
+
+        return d * Math.PI / 180.0;
+
+    }
+
+    public static double getDistance(double lat1, double lng1, double lat2,
+
+                                     double lng2) {
+
+        double radLat1 = rad(lat1);
+
+        double radLat2 = rad(lat2);
+
+        double a = radLat1 - radLat2;
+
+        double b = rad(lng1) - rad(lng2);
+
+        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
+
+                + Math.cos(radLat1) * Math.cos(radLat2)
+
+                * Math.pow(Math.sin(b / 2), 2)));
+
+        s = s * EARTH_RADIUS;
+
+        s = Math.round(s * 10000) / 10000;
+
+        return s;
+
+    }
+
+    public static void main(String[] args) {
+        double lat1 = 118.105736;
+        double lng1 = 24.491558;
+        double lat2 = 118.110749;
+        double lng2 = 24.492824;
+        double t = getDistance(lat1, lng1, lat2, lng2);
+        System.out.println(t);
+    }
+
+}

+ 133 - 0
src/main/java/com/caimei/util/ProductUtils.java

@@ -0,0 +1,133 @@
+package com.caimei.util;
+
+import org.springframework.util.StringUtils;
+
+/**
+ * Description
+ *
+ * @author : Charles
+ * @date : 2020/3/25
+ */
+public class ProductUtils {
+    public static String getImageURL(String dirName, String src, String domain) {
+        return getImageURL(dirName, src, 0, domain);
+    }
+
+    /***
+     * 获取图片地址
+     *
+     * @param src
+     *            保存在数据库中的图片文件名
+     * @param type
+     *            图片的前缀 (如 type = 200 那么则获取的图片是 200_XXX的图片)
+     * @param dirName
+     *            图片保存的文件夹名 如 (league)
+     * @param domain
+     * 			   加上域名拼成完整路径
+     * @return
+     */
+    public static String getImageURL(String dirName, String src, int type, String domain) {
+
+
+        //正式环境 域名 http --- https处理
+        if (domain != null && !"".equals(domain) && domain.startsWith("http:") && domain.toLowerCase().lastIndexOf("test") == -1 && domain.toLowerCase().lastIndexOf("localhost") == -1) {
+            domain = domain.replace("http:", "https:");
+        }
+
+        //正式环境 图片地址 http --- https处理
+        if (src != null && src.startsWith("https:")) {
+            //非正式环境 使用http
+            if (domain != null && !"".equals(domain) && domain.toLowerCase().lastIndexOf("test") > -1 || domain.toLowerCase().lastIndexOf("localhost") > -1) {
+                src = src.replace("https:", "http:");
+            }
+            return src;
+        }
+
+        //正式环境 图片地址  http --- https处理
+        if (src != null && src.startsWith("http:")) {
+            //非正式环境 使用http
+            if (domain != null && !"".equals(domain) && domain.toLowerCase().lastIndexOf("test") == -1 && domain.toLowerCase().lastIndexOf("localhost") == -1) {
+                src = src.replace("http:", "https:");
+            }
+            return src;
+        }
+        type = 0;
+        dirName = dirName.trim();
+        if (dirName == null) {
+            dirName = "";
+        }
+        if (src == null || src.equalsIgnoreCase("null")) {
+            src = "";
+        }
+        if (src.indexOf(",") > 0) {
+            String tmp = src;
+            src = tmp.substring(0, tmp.indexOf(","));
+        }
+        String image = "/img/default/none.jpg";
+        if (dirName.equals("user")) {
+            image = "/img/default/HeaderImg.png";
+        } else if (dirName.equals("club")) {
+            image = "/img/default/default_club.jpg";
+        } else if (dirName.equals("shopLogo")) {
+            image = "/img/default/suppliver.jpg";
+        } else if (dirName.equals("caiMeiImage")) {
+            image = "/img/default/caiMeiImage.jpg";
+        } else {
+            image = "/img/default/none.jpg";
+        }
+        if (src != null && !src.equals("")) {
+            if (type != 0 || dirName.equals("product")) {
+                src = src.replace("\\", "/");
+                String srcActual = src;
+                String subDirName = "";
+                int index = src.lastIndexOf("/");
+
+                if (index != -1) {
+                    subDirName = src.substring(0, index + 1);
+                    srcActual = src.substring(index + 1);
+                }
+                boolean b = src.startsWith("/uploadFile");
+                if (b) {
+                    image = src;
+                } else {
+                    image = "/uploadFile/" + dirName + "/" + subDirName
+                            + (type == 0 ? "" : type + "_") + srcActual;
+                }
+            } else {
+                boolean b = src.startsWith("/uploadFile");
+                if (b) {
+                    image = src;
+                } else {
+                    image = "/uploadFile/" + dirName + "/" + src;
+                }
+            }
+        } else {
+            if (StringUtils.isEmpty(image)) {
+                image = "/img/default/none.jpg";
+            }
+        }
+        return domain + image;
+    }
+
+    public static String getProductImageURL(String image, int type, String domain) {
+        if (image == null) {
+            return getImageURL("product", "", type, domain);
+        }
+        return getImageURL("product", image, type, domain);
+    }
+
+    public static String getPriceGrade(Double price) {
+        if (price <= 2.5 * 10000L) {
+            return "1";
+        } else if (price <= 10 * 10000) {
+            return "2";
+        } else if (price <= 25 * 10000) {
+            return "3";
+        } else if (price <= 50 * 10000) {
+            return "4";
+        } else {
+            return "5";
+        }
+    }
+
+}

+ 18 - 3
src/main/resources/backup.sql

@@ -1,9 +1,11 @@
 CREATE TABLE `cm_hehe_user`(
   `id` INT NOT NULL AUTO_INCREMENT,
+  `userId` INT NULL   COMMENT '对应user表用户id',
   `name` VARCHAR(30) COMMENT '姓名',
   `mobile` VARCHAR(20) COMMENT '手机号',
   `userIdentity` CHAR(2) COMMENT '用户身份:1普通用户,2分销者',
   `nickName` VARCHAR(32) COMMENT '微信昵称',
+  `headImgUrl` TEXT NULL   COMMENT '头像',
   `openId` VARCHAR(32) COMMENT '微信openid',
   `addTime` DATETIME COMMENT '添加时间',
   PRIMARY KEY (`id`)
@@ -39,7 +41,6 @@ COMMENT='呵呵商城轮播图表';
 
 CREATE TABLE `cm_hehe_activity`(
   `id` INT NOT NULL AUTO_INCREMENT,
-  `userId` INT COMMENT '分销者用户id',
   `name` VARCHAR(50) COMMENT '活动名称',
   `status` CHAR(1) COMMENT '小程序状态:1启用,2停用',
   `listImage` TEXT COMMENT '小程序列表缩略图',
@@ -56,7 +57,6 @@ CREATE TABLE `cm_hehe_activity_product`(
   `id` INT NOT NULL AUTO_INCREMENT,
   `activityId` INT COMMENT '呵呵活动id',
   `productId` INT COMMENT '对应采美商品id',
-  `sort` INT COMMENT '排序值',
   `addTime` DATETIME COMMENT '添加时间',
   `delFlag` CHAR(1) COMMENT '删除标识:0未删除,1已删除',
   PRIMARY KEY (`id`)
@@ -73,4 +73,19 @@ CREATE TABLE `cm_hehe_activity_ladder`(
   `createDate` DATETIME COMMENT '创建时间',
   PRIMARY KEY (`id`)
 ) ENGINE=INNODB CHARSET=utf8mb4
-COMMENT='呵呵商城活动阶梯表';
+COMMENT='呵呵商城活动阶梯表';
+
+ALTER TABLE `user`
+  CHANGE `userPermission` `userPermission` INT DEFAULT 0  NULL   COMMENT '用户权限 0游客 1 普通用户 2 会员机构 3 供应商 4 协销 5 普通机构 6 呵呵商城用户【V6.2.0版本后0和1不存在】',
+  CHANGE `userIdentity` `userIdentity` INT DEFAULT 0  NULL   COMMENT '用户身份 0、个人 1、协销 2、会员机构 3、供应商 4.普通机构 6、呵呵商城用户【V6.2.0版本后0不存在】';
+
+CREATE TABLE `cm_hehe_user_activity`(
+  `id` INT NOT NULL AUTO_INCREMENT,
+  `userId` INT COMMENT '用户id',
+  `activityId` INT COMMENT '活动id',
+  `productId` INT COMMENT '商品id',
+  `sort` INT COMMENT '排序值',
+  `addTime` DATETIME NULL COMMENT '添加时间',
+  PRIMARY KEY (`id`)
+) ENGINE=INNODB CHARSET=utf8mb4
+COMMENT='呵呵分销用户活动商品表';

+ 5 - 5
src/main/resources/config/beta/application-beta.yml

@@ -36,10 +36,8 @@ swagger:
 
 #自定义配置
 wx:
-  AppId: wxca7172d7a20bdf7a
-  AppSecret: d7f853a64b73d01ef93f3829852a790e
-  crmAppId: wxea43a0f9ebce9e66
-  crmAppSecret: 1c3cd60908e72dd280840bee9e15f7f6
+  AppId: wx2c3b0a7f343235b1
+  AppSecret: 1bb87882ee85a0411923d7f56c7dde75
 
 # 新旧www服务域名
 caimei:
@@ -47,4 +45,6 @@ caimei:
   #支付异步回调地址
   notifyUrl: https://spi-b.caimei365.com/PayOrder/paymentCallback
   #支付链接重定向地址
-  redirectLink: https://spi-b.caimei365.com/PayOrder/jumpPage
+  redirectLink: https://spi-b.caimei365.com/PayOrder/jumpPage
+  #微服务网关地址
+  userUrl: http://localhost:18002

+ 5 - 5
src/main/resources/config/dev/application-dev.yml

@@ -35,10 +35,8 @@ swagger:
 
 #自定义配置
 wx:
-  AppId: wxca7172d7a20bdf7a
-  AppSecret: d7f853a64b73d01ef93f3829852a790e
-  crmAppId: wxea43a0f9ebce9e66
-  crmAppSecret: 1c3cd60908e72dd280840bee9e15f7f6
+  AppId: wx2c3b0a7f343235b1
+  AppSecret: 1bb87882ee85a0411923d7f56c7dde75
 
 # 新旧www服务域名
 caimei:
@@ -46,4 +44,6 @@ caimei:
   #支付异步回调地址
   notifyUrl: https://spi-b.caimei365.com/PayOrder/paymentCallback
   #支付链接重定向地址
-  redirectLink: https://spi-b.caimei365.com/PayOrder/jumpPage
+  redirectLink: https://spi-b.caimei365.com/PayOrder/jumpPage
+  #微服务网关地址
+  userUrl: http://localhost:18002

+ 4 - 4
src/main/resources/config/prod/application-prod.yml

@@ -37,10 +37,8 @@ swagger:
 
 #自定义配置
 wx:
-  AppId: wxca7172d7a20bdf7a
-  AppSecret: d7f853a64b73d01ef93f3829852a790e
-  crmAppId: wxea43a0f9ebce9e66
-  crmAppSecret: 1c3cd60908e72dd280840bee9e15f7f6
+  AppId: wx2c3b0a7f343235b1
+  AppSecret: 1bb87882ee85a0411923d7f56c7dde75
 
 # 新旧www服务域名
 caimei:
@@ -49,3 +47,5 @@ caimei:
   notifyUrl: https://spi.caimei365.com/PayOrder/paymentCallback
   #支付链接重定向地址
   redirectLink: https://spi.caimei365.com/PayOrder/jumpPage
+  #微服务网关地址
+  userUrl: http://localhost:18002

+ 114 - 0
src/main/resources/mapper/AddressMapper.xml

@@ -0,0 +1,114 @@
+<?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.caimei.mapper.AddressMapper">
+    <select id="findAddress" resultType="com.caimei.model.vo.AddressVo">
+        SELECT a.addressID AS addressId,
+               a.userID AS userId,
+               a.shouHuoRen,
+               a.townID AS townId,
+               a.address,
+               a.postalCode,
+               a.phone,
+               a.mobile,
+               a.defaultFlag,
+               c.cityID AS cityId,
+               p.provinceID AS provinceId,
+               t.name AS townName,
+               c.name AS cityName,
+               p.name AS provinceName
+        FROM address a
+                 LEFT JOIN town t ON t.townID = a.townID
+                 LEFT JOIN city c ON c.cityID = t.cityID
+                 LEFT JOIN province p ON p.provinceID = c.provinceID
+        WHERE a.userID = #{userId}
+        ORDER BY
+          defaultFlag DESC,
+          addressID ASC
+    </select>
+
+    <select id="findDefaultAddress" resultType="com.caimei.model.vo.AddressVo">
+        SELECT
+          addressID AS addressId,
+          userID AS userId,
+          shouHuoRen,
+          townID AS townId,
+          address,
+          postalCode,
+          phone,
+          mobile,
+          defaultFlag
+        FROM
+          address
+        WHERE
+          userID = #{userId}
+          AND defaultFlag = '1'
+    </select>
+
+    <update id="updateAddress">
+        UPDATE
+          address
+        SET
+          shouHuoRen =#{shouHuoRen},
+          townID = #{townId},
+          address = #{address},
+          mobile = #{mobile},
+          defaultFlag = #{defaultFlag}
+        WHERE
+          addressID = #{addressId}
+    </update>
+
+    <insert id="insertAddress" useGeneratedKeys="true" keyProperty="addressId" keyColumn="addressID" parameterType="com.caimei.model.vo.AddressVo">
+        INSERT INTO address (
+          userID, shouHuoRen, townID, address,
+          mobile, defaultFlag
+        )
+        VALUES
+          (
+            #{userId},#{shouHuoRen},#{townId},
+            #{address},#{mobile},#{defaultFlag}
+          )
+    </insert>
+
+    <delete id="deleteAddress">
+        DELETE FROM address WHERE addressID = #{addressId}
+    </delete>
+
+    <update id="updateDefaultAddress">
+        UPDATE address SET defaultFlag = '1' WHERE addressID = #{addressId}
+    </update>
+
+    <select id="findAllProvince" resultType="com.caimei.model.vo.ProvinceVo">
+        SELECT
+          provinceID AS provinceId,
+          name
+        FROM
+          province
+        WHERE
+          validFlag = '1'
+    </select>
+
+    <select id="findAllCity" resultType="com.caimei.model.vo.CityVo">
+        SELECT
+          cityID AS cityId,
+          provinceID AS provinceId,
+          name
+        FROM
+          city
+        WHERE
+          provinceID = #{provinceId}
+          AND validFlag = '1'
+    </select>
+
+    <select id="findAllTown" resultType="com.caimei.model.vo.TownVo">
+        SELECT
+          townID AS townId,
+          name
+        FROM
+          town
+        WHERE
+          cityID = #{cityId}
+          AND validFlag = '1'
+    </select>
+</mapper>

+ 196 - 0
src/main/resources/mapper/ProductMapper.xml

@@ -0,0 +1,196 @@
+<?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.caimei.mapper.ProductMapper">
+    <select id="findImageAll" resultType="string">
+        SELECT
+          image
+        FROM
+          cm_hehe_image
+        WHERE
+          status = 1
+        ORDER BY
+          - sort DESC
+    </select>
+
+    <select id="findProductList" resultType="com.caimei.model.vo.ProductVo">
+        SELECT
+          a.productId,
+          a.recommend,
+          a.price,
+          a.includedTax,
+          a.invoiceType,
+          a.clubTaxPoint,
+          p.name,
+          p.mainImage
+        FROM
+          cm_hehe_product a
+          LEFT JOIN product p ON a.productId = p.productID
+        WHERE
+          a.validFlag = 1
+          <if test="name != null and name != ''">
+              AND p.name LIKE CONCAT('%',#{name},'%')
+          </if>
+        ORDER BY
+          a.recommend DESC,
+          a.addTime DESC
+    </select>
+
+    <select id="findActivityByProductId" resultType="integer">
+        SELECT
+          activityId
+        FROM
+          cm_hehe_activity_product a
+          LEFT JOIN cm_hehe_activity cha ON a.activityId = cha.id
+        WHERE
+          cha.delFlag = 0
+          AND a.delFlag = 0
+          AND NOW() BETWEEN cha.beginTime
+          AND cha.endTime
+          AND a.productId = #{productId}
+    </select>
+
+    <select id="findActivityLadder" resultType="com.caimei.model.vo.ActivityLadderVo">
+        SELECT
+          buyNum,
+          buyPrice
+        FROM
+          cm_hehe_activity_ladder
+        WHERE
+          activityId = #{activityId}
+          AND productId = #{productId}
+        ORDER BY
+          ladderNum
+    </select>
+    
+    <select id="findProductByProductId" resultType="com.caimei.model.vo.ProductDetailsVo">
+        SELECT
+          a.productId,
+          a.recommend,
+          a.price,
+          a.includedTax,
+          a.invoiceType,
+          a.clubTaxPoint,
+          p.name,
+          p.mainImage,
+          p.brandID AS "brandId",
+          p.bigTypeID AS "bigTypeId",
+          p.smallTypeID AS "smallTypeId",
+          p.tinyTypeID AS "tinyTypeId",
+          P.unit,
+          p.tags,
+        FROM
+          cm_hehe_product a
+          LEFT JOIN product p ON a.productId = p.productID
+        WHERE
+          a.productId = #{productId}
+    </select>
+
+    <select id="findProductImages" resultType="string">
+        SELECT
+          image
+        FROM
+          productimage
+        WHERE
+          productID = #{productId}
+        ORDER BY
+          mainFlag DESC
+    </select>
+
+    <select id="findProductDetail" resultType="com.caimei.model.po.ProductDetailInfoPo">
+        select
+          productDetailInfoID as productDetailInfoId,
+          productID as productId,
+          propValueAlias,
+          propValueImages,
+          detailInfo,
+          detailInfoTxt,
+          seoTitle,
+          seoKeyword,
+          seoDes,
+          serviceInfo,
+          orderInfo
+        from
+          productdetailinfo
+        where
+          productID = #{productId}
+    </select>
+
+    <select id="findTypeName" resultType="string">
+        SELECT
+          CONCAT_WS('-', b.name, s.name, t.name)
+        FROM
+          bigtype b
+          LEFT JOIN smalltype s ON s.smallTypeID = #{smallTypeId}
+          LEFT JOIN tinytype t ON t.tinyTypeID = #{tinyTypeId}
+        WHERE
+          b.bigTypeID = #{bigTypeId}
+    </select>
+    
+    <select id="findBrandName" resultType="string">
+        SELECT
+          name
+        FROM
+          cm_brand
+        WHERE
+          id = #{brandId}
+          and delFlag = '0'
+          and status = '1'
+    </select>
+
+    <select id="findParameters" resultType="com.caimei.model.vo.RelatedParametersVo">
+        SELECT
+          paramsName,
+          paramsContent
+        FROM
+          cm_product_related_parameters
+        WHERE
+          productId = #{productId}
+          AND delFlag = '0'
+    </select>
+
+    <select id="findSearchHistory" resultType="integer">
+        SELECT id FROM user_search_history WHERE searchWord = #{name} LIMIT 1
+    </select>
+
+    <update id="updateHistoryByDate">
+        UPDATE SET searchDate = NOW() WHERE id = #{recordId}
+    </update>
+
+    <insert id="insertSearchHistory">
+        INSERT INTO `user_search_history` (
+          `userId`, `searchWord`, `searchDate`,
+          `delFlag`
+        )
+        VALUES
+          (
+            #{userId}, #{searchWord}, #{searchDate},
+            #{delFlag}
+          )
+    </insert>
+
+    <select id="searchHistory" resultType="string">
+        SELECT
+          searchWord
+        FROM
+          user_search_history
+        WHERE
+          userId = #{userId}
+        ORDER BY
+          searchDate DESC
+        LIMIT
+          10
+    </select>
+
+    <delete id="deleteHistoryByUserId">
+        DELETE FROM user_search_history
+        WHERE userId=#{userId}
+        AND id NOT IN (
+            SELECT temp.id FROM (
+                SELECT id FROM user_search_history WHERE userId=#{userId} ORDER BY id DESC LIMIT 10
+            ) AS temp
+        )
+    </delete>
+
+</mapper>