优惠券模块新用户接口开发

商品服务模块脚手架搭建
轮播图list接口开发
This commit is contained in:
jieyuu 2024-08-09 12:51:38 +08:00
parent 589c6dee0b
commit 48b1148192
24 changed files with 587 additions and 8 deletions

View File

@ -18,7 +18,7 @@ public class InterceptorConfig implements WebMvcConfigurer {
//拦截的路径 //拦截的路径
.addPathPatterns("/api/coupon/*/**","/api/coupon_record/v1/*/**") .addPathPatterns("/api/coupon/*/**","/api/coupon_record/v1/*/**")
//放行的路径 //放行的路径
.excludePathPatterns("/api/coupon/*/page_coupon"); .excludePathPatterns("/api/coupon/*/page_coupon","/api/coupon/*/initNewUserCoupon");
WebMvcConfigurer.super.addInterceptors(registry); WebMvcConfigurer.super.addInterceptors(registry);
} }

View File

@ -4,6 +4,7 @@ package net.jieyuu.controller;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiParam;
import net.jieyuu.enums.CouponCategoryEnum; import net.jieyuu.enums.CouponCategoryEnum;
import net.jieyuu.request.NewUserRequest;
import net.jieyuu.service.CouponService; import net.jieyuu.service.CouponService;
import net.jieyuu.utils.JsonData; import net.jieyuu.utils.JsonData;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -39,16 +40,23 @@ public class CouponController {
} }
@ApiOperation("领取优惠券") @ApiOperation("领取优惠券")
@GetMapping("add/promotion/{coupon_id}") @GetMapping("add/promotion/{coupon_id}")
public JsonData addPromotionCoupon( public JsonData addPromotionCoupon(
@ApiParam(value = "优惠券id",required = true) @ApiParam(value = "优惠券id", required = true)
@PathVariable("coupon_id")long couponId) { @PathVariable("coupon_id") long couponId) {
JsonData jsonData = couponService.addCoupon(couponId, CouponCategoryEnum.PROMOTION); JsonData jsonData = couponService.addCoupon(couponId, CouponCategoryEnum.PROMOTION);
return jsonData; return jsonData;
} }
@ApiOperation("拉新发放优惠券")
@PostMapping("new_user_coupon")
public JsonData addNewUserCoupon(@ApiParam("用户对象") @RequestBody NewUserRequest newUserRequest) {
JsonData jsonData = couponService.initNewUserCoupon(newUserRequest);
return jsonData;
}
} }

View File

@ -0,0 +1,21 @@
package net.jieyuu.request;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ApiModel
@Data
public class NewUserRequest {
@ApiModelProperty(value = "新用户注册id", example = "19")
@JsonProperty("user_id")
private long userId;
@ApiModelProperty(value = "名称", example = "jieyuu")
@JsonProperty("name")
private String name;
}

View File

@ -2,6 +2,7 @@ package net.jieyuu.service;
import net.jieyuu.enums.CouponCategoryEnum; import net.jieyuu.enums.CouponCategoryEnum;
import net.jieyuu.request.NewUserRequest;
import net.jieyuu.utils.JsonData; import net.jieyuu.utils.JsonData;
import java.util.Map; import java.util.Map;
@ -31,4 +32,11 @@ public interface CouponService {
* @return * @return
*/ */
JsonData addCoupon(long couponId, CouponCategoryEnum couponCategoryEnum); JsonData addCoupon(long couponId, CouponCategoryEnum couponCategoryEnum);
/**
* 新用户注册发放优惠券
* @param newUserRequest
* @return
*/
JsonData initNewUserCoupon(NewUserRequest newUserRequest);
} }

View File

@ -15,6 +15,7 @@ import net.jieyuu.model.CouponDO;
import net.jieyuu.mapper.CouponMapper; import net.jieyuu.mapper.CouponMapper;
import net.jieyuu.model.CouponRecordDO; import net.jieyuu.model.CouponRecordDO;
import net.jieyuu.model.LoginUser; import net.jieyuu.model.LoginUser;
import net.jieyuu.request.NewUserRequest;
import net.jieyuu.service.CouponService; import net.jieyuu.service.CouponService;
import net.jieyuu.utils.CommonUtil; import net.jieyuu.utils.CommonUtil;
import net.jieyuu.utils.JsonData; import net.jieyuu.utils.JsonData;
@ -26,8 +27,10 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -128,6 +131,34 @@ public class CouponServiceImpl implements CouponService {
return JsonData.buildSuccess(); return JsonData.buildSuccess();
} }
/**
* 微服务调用时没登录没有token
* <p>
* 本地发放优惠券需要构造token存入threadlocal
*
* @param newUserRequest
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public JsonData initNewUserCoupon(NewUserRequest newUserRequest) {
LoginUser loginUser = new LoginUser();
loginUser.setName(newUserRequest.getName());
loginUser.setId(newUserRequest.getUserId());
// 发放优惠券接口需要threadlocal
LoginInterceptor.threadLocal.set(loginUser);
List<CouponDO> couponList = couponMapper.selectList(new QueryWrapper<CouponDO>()
.eq("category", CouponCategoryEnum.NEW_USER.name()));
for (CouponDO couponDO : couponList) {
// 幂等操作 调用需要加锁
// 发放
this.addCoupon(couponDO.getId(), CouponCategoryEnum.NEW_USER);
}
return JsonData.buildSuccess();
}
/** /**
* 校验优惠券是否可以领取 * 校验优惠券是否可以领取
* *

View File

@ -48,7 +48,6 @@ public class MyBatisPlusGenerator {
// 设置数据库类型 // 设置数据库类型
dsConfig.setDbType(DbType.MYSQL) dsConfig.setDbType(DbType.MYSQL)
.setDriverName("com.mysql.cj.jdbc.Driver") .setDriverName("com.mysql.cj.jdbc.Driver")
//TODO TODO TODO TODO
.setUrl("jdbc:mysql://134.175.219.253:3306/xdclass_coupon?useSSL=false") .setUrl("jdbc:mysql://134.175.219.253:3306/xdclass_coupon?useSSL=false")
.setUsername("root") .setUsername("root")
.setPassword("59ae8683c59fead903132a8d440bd7d9fd4936529d1d6f45f9d41111d7537bdd"); .setPassword("59ae8683c59fead903132a8d440bd7d9fd4936529d1d6f45f9d41111d7537bdd");

View File

@ -11,6 +11,13 @@
<artifactId>xdclass-product-service</artifactId> <artifactId>xdclass-product-service</artifactId>
<dependencies>
<dependency>
<groupId>net.jieyuu</groupId>
<artifactId>xdclass-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<properties> <properties>
<maven.compiler.source>8</maven.compiler.source> <maven.compiler.source>8</maven.compiler.source>

View File

@ -0,0 +1,15 @@
package net.jieyuu;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication
@EnableTransactionManagement
@MapperScan("net.jieyuu.mapper")
public class ProductApplication {
public static void main(String[] args) {
SpringApplication.run(ProductApplication.class, args);
}
}

View File

@ -0,0 +1,38 @@
package net.jieyuu.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import net.jieyuu.service.BannerService;
import net.jieyuu.utils.JsonData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 前端控制器
* </p>
*
* @author jieyuu
* @since 2024-08-07
*/
@Api("轮播图模块")
@RestController
@RequestMapping("/api/banner/v1")
public class BannerController {
@Autowired
private BannerService bannerService;
@ApiOperation("轮播图列表接口")
@GetMapping("list")
public JsonData list() {
return JsonData.buildSuccess(bannerService.list());
}
}

View File

@ -0,0 +1,21 @@
package net.jieyuu.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 前端控制器
* </p>
*
* @author jieyuu
* @since 2024-08-07
*/
@RestController
@RequestMapping("/productDO")
public class ProductController {
}

View File

@ -0,0 +1,16 @@
package net.jieyuu.mapper;
import net.jieyuu.model.BannerDO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author jieyuu
* @since 2024-08-07
*/
public interface BannerMapper extends BaseMapper<BannerDO> {
}

View File

@ -0,0 +1,16 @@
package net.jieyuu.mapper;
import net.jieyuu.model.ProductDO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author jieyuu
* @since 2024-08-07
*/
public interface ProductMapper extends BaseMapper<ProductDO> {
}

View File

@ -0,0 +1,44 @@
package net.jieyuu.model;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
*
* </p>
*
* @author jieyuu
* @since 2024-08-07
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("banner")
public class BannerDO implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 图片
*/
private String img;
/**
* 跳转地址
*/
private String url;
/**
* 权重
*/
private Integer weight;
}

View File

@ -0,0 +1,71 @@
package net.jieyuu.model;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
*
* </p>
*
* @author jieyuu
* @since 2024-08-07
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("product")
public class ProductDO implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 标题
*/
private String title;
/**
* 封面图
*/
private String coverImg;
/**
* 详情
*/
private String detail;
/**
* 老价格
*/
private BigDecimal oldPrice;
/**
* 新价格
*/
private BigDecimal price;
/**
* 库存
*/
private Integer stock;
/**
* 创建时间
*/
private Date createTime;
/**
* 锁定库存
*/
private Integer lockStock;
}

View File

@ -0,0 +1,21 @@
package net.jieyuu.service;
import net.jieyuu.model.BannerDO;
import com.baomidou.mybatisplus.extension.service.IService;
import net.jieyuu.vo.BannerVO;
import java.util.List;
/**
* <p>
* 服务类
* </p>
*
* @author jieyuu
* @since 2024-08-07
*/
public interface BannerService {
List<BannerVO> list();
}

View File

@ -0,0 +1,16 @@
package net.jieyuu.service;
import net.jieyuu.model.ProductDO;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 服务类
* </p>
*
* @author jieyuu
* @since 2024-08-07
*/
public interface ProductService extends IService<ProductDO> {
}

View File

@ -0,0 +1,43 @@
package net.jieyuu.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import net.jieyuu.model.BannerDO;
import net.jieyuu.mapper.BannerMapper;
import net.jieyuu.service.BannerService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.jieyuu.vo.BannerVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>
* 服务实现类
* </p>
*
* @author jieyuu
* @since 2024-08-07
*/
@Service
public class BannerServiceImpl implements BannerService {
@Autowired
private BannerMapper bannerMapper;
@Override
public List<BannerVO> list() {
List<BannerDO> bannerDOList = bannerMapper.selectList(new QueryWrapper<BannerDO>().orderByAsc("weight"));
List<BannerVO> bannerVOList = bannerDOList.stream().map(obj -> {
BannerVO bannerVO = new BannerVO();
BeanUtils.copyProperties(obj, bannerVO);
return bannerVO;
}).collect(Collectors.toList());
return bannerVOList;
}
}

View File

@ -0,0 +1,20 @@
package net.jieyuu.service.impl;
import net.jieyuu.model.ProductDO;
import net.jieyuu.mapper.ProductMapper;
import net.jieyuu.service.ProductService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 服务实现类
* </p>
*
* @author jieyuu
* @since 2024-08-07
*/
@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductDO> implements ProductService {
}

View File

@ -0,0 +1,26 @@
package net.jieyuu.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public class BannerVO {
private Integer id;
/**
* 图片
*/
private String img;
/**
* 跳转地址
*/
private String url;
/**
* 权重
*/
private Integer weight;
}

View File

@ -0,0 +1,29 @@
server:
port: 9003
spring:
application:
name: xdclass_product-service
#数据库配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://134.175.219.253:3306/xdclass_product?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 59ae8683c59fead903132a8d440bd7d9fd4936529d1d6f45f9d41111d7537bdd
redis:
host: 134.175.219.253
password: 123456
port: 8000
#配置plus打印sql日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#设置日志级别,ERROR/WARN/INFO/DEBUG,默认是INFO以上才显示
logging:
level:
root: INFO

View File

@ -0,0 +1,18 @@
<?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="net.jieyuu.mapper.BannerMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="net.jieyuu.model.BannerDO">
<id column="id" property="id" />
<result column="img" property="img" />
<result column="url" property="url" />
<result column="weight" property="weight" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, img, url, weight
</sql>
</mapper>

View File

@ -0,0 +1,23 @@
<?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="net.jieyuu.mapper.ProductMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="net.jieyuu.model.ProductDO">
<id column="id" property="id" />
<result column="title" property="title" />
<result column="cover_img" property="coverImg" />
<result column="detail" property="detail" />
<result column="old_price" property="oldPrice" />
<result column="price" property="price" />
<result column="stock" property="stock" />
<result column="create_time" property="createTime" />
<result column="lock_stock" property="lockStock" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, title, cover_img, detail, old_price, price, stock, create_time, lock_stock
</sql>
</mapper>

View File

@ -0,0 +1,91 @@
package net.jieyuu.db;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
public class MyBatisPlusGenerator {
public static void main(String[] args) {
//1. 全局配置
GlobalConfig config = new GlobalConfig();
// 作者
config.setAuthor("jieyuu")
// 生成路径最好使用绝对路径window路径是不一样的
.setOutputDir("D:\\workspace\\project\\xdclass-shop\\xdclass-shop\\xdclass-product-service\\src\\main\\java")
// 文件覆盖
.setFileOverride(true)
// 主键策略
.setIdType(IdType.AUTO)
.setDateType(DateType.ONLY_DATE)
// 设置生成的service接口的名字的首字母是否为I默认Service是以I开头的
.setServiceName("%sService")
//实体类结尾名称
.setEntityName("%sDO")
//生成基本的resultMap
.setBaseResultMap(true)
//不使用AR模式
.setActiveRecord(false)
//生成基本的SQL片段
.setBaseColumnList(true);
//2. 数据源配置
DataSourceConfig dsConfig = new DataSourceConfig();
// 设置数据库类型
dsConfig.setDbType(DbType.MYSQL)
.setDriverName("com.mysql.cj.jdbc.Driver")
.setUrl("jdbc:mysql://134.175.219.253:3306/xdclass_product?useSSL=false")
.setUsername("root")
.setPassword("59ae8683c59fead903132a8d440bd7d9fd4936529d1d6f45f9d41111d7537bdd");
//3. 策略配置globalConfiguration中
StrategyConfig stConfig = new StrategyConfig();
//全局大写命名
stConfig.setCapitalMode(true)
// 数据库表映射到实体的命名策略
.setNaming(NamingStrategy.underline_to_camel)
//使用lombok
.setEntityLombokModel(true)
//使用restcontroller注解
.setRestControllerStyle(true)
// 生成的表, 支持多表一起生成以数组形式填写
.setInclude("banner", "product");
//4. 包名策略配置
PackageConfig pkConfig = new PackageConfig();
pkConfig.setParent("net.jieyuu")
.setMapper("mapper")
.setService("service")
.setController("controller")
.setEntity("model")
.setXml("mapper");
//5. 整合配置
AutoGenerator ag = new AutoGenerator();
ag.setGlobalConfig(config)
.setDataSource(dsConfig)
.setStrategy(stConfig)
.setPackageInfo(pkConfig);
//6. 执行操作
ag.execute();
System.out.println("======= 小滴课堂 Done 相关代码生成完毕 ========");
}
}

View File

@ -20,7 +20,6 @@ public class MyBatisPlusGenerator {
// 作者 // 作者
.setAuthor("jieyuu") .setAuthor("jieyuu")
// 生成路径最好使用绝对路径window路径是不一样的 // 生成路径最好使用绝对路径window路径是不一样的
//TODO TODO TODO TODO
.setOutputDir("D:\\workspace\\project\\xdclass-shop\\xdclass-shop\\xdclass-user-service\\src\\main\\java") .setOutputDir("D:\\workspace\\project\\xdclass-shop\\xdclass-shop\\xdclass-user-service\\src\\main\\java")
// 文件覆盖 // 文件覆盖
.setFileOverride(true) .setFileOverride(true)
@ -48,7 +47,6 @@ public class MyBatisPlusGenerator {
// 设置数据库类型 // 设置数据库类型
dsConfig.setDbType(DbType.MYSQL) dsConfig.setDbType(DbType.MYSQL)
.setDriverName("com.mysql.cj.jdbc.Driver") .setDriverName("com.mysql.cj.jdbc.Driver")
//TODO TODO TODO TODO
.setUrl("jdbc:mysql://134.175.219.253:3306/xdclass_user?useSSL=false") .setUrl("jdbc:mysql://134.175.219.253:3306/xdclass_user?useSSL=false")
.setUsername("root") .setUsername("root")
.setPassword("59ae8683c59fead903132a8d440bd7d9fd4936529d1d6f45f9d41111d7537bdd"); .setPassword("59ae8683c59fead903132a8d440bd7d9fd4936529d1d6f45f9d41111d7537bdd");
@ -68,7 +66,6 @@ public class MyBatisPlusGenerator {
.setRestControllerStyle(true) .setRestControllerStyle(true)
// 生成的表, 支持多表一起生成以数组形式填写 // 生成的表, 支持多表一起生成以数组形式填写
//TODO TODO TODO TODO
.setInclude("user","address"); .setInclude("user","address");
//4. 包名策略配置 //4. 包名策略配置