京东秒杀之商品展示

1 在gitee上添加.yml文件

1.1 添加good-server.yml文件

server:
  port: 8084
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/shop_goods?serverTimezone=GMT%2B8
    driverClassName: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    username: root
    password: 123456
mybatis:
  configuration:
    default-fetch-size: 100
    default-statement-timeout: 3000
    map-underscore-to-camel-case: true

1.2 添加seckill-server.yml文件

在这里插入图片描述

server:
  port: 8085
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/shop_seckill?serverTimezone=GMT%2B8
    driverClassName: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    username: root
    password: 123456
mybatis:
  configuration:
    default-fetch-size: 100
    default-statement-timeout: 3000
    map-underscore-to-camel-case: true

2 创建启动类

2.1 创建商品服务启动类

@SpringBootApplication
@EnableEurekaClient
public class GoodServerApp {
    public static void main(String[] args) {
        SpringApplication.run(GoodServerApp.class, args);
    }
}

2.2 创建秒杀启动类

在这里插入图片描述

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class SeckillServerApp {
    public static void main(String[] args) {
        SpringApplication.run(SeckillServerApp.class, args);
    }
}

3 编写前端商品页面

<!DOCTYPE html>
<html lang="en">
<head>
    <title>商品列表</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <script type="text/javascript" src="/js/jquery.min.js"></script>
    <link rel="stylesheet" type="text/css" href="/bootstrap/css/bootstrap.min.css" /><!-- bootstrap -->
    <script type="text/javascript" src="/bootstrap/js/bootstrap.min.js"></script>
    <script type="text/javascript" src="/jquery-validation/jquery.validate.min.js"></script> <!-- jquery-validator -->
    <script type="text/javascript" src="/jquery-validation/localization/messages_zh.min.js"></script>
    <script type="text/javascript" src="/layer/layer.js"></script><!-- layer -->
    <script type="text/javascript" src="/js/md5.min.js"></script><!-- md5.js -->
    <script type="text/javascript" src="/js/common.js"></script><!-- common.js -->
</head>
<body>
<div class="panel panel-default">
    <div class="panel-heading">秒杀商品列表</div>
    <table class="table" id="goodlist">
        <tr><td>商品名称</td><td>商品图片</td><td>商品原价</td><td>秒杀价</td><td>库存数量</td><td>详情</td></tr>
    </table>
</div>

<script type="text/javascript">
    String.prototype.format=function () {
        if(arguments.length==0){
            return this;
        }
        var obj=arguments[0];
        var s = this;

        for(var key in obj){
            s= s.replace(new RegExp("\\{\\{"+key+"\\}\\}","g"),obj[key]);
        }
        return s;
    };


    var template="<tr><td>{{goodName}}</td>" +
        "<td><img src='{{goodImg}}' width='100px' height='100px' /> </td>" +
        "<td>{{goodPrice}}</td>" +
        "<td>{{seckillPrice}}</td>" +
        "<td>{{stockCount}}</td>" +
        "<td> <a href='good_detail.html?seckillId={{id}}'>详情</a> </td></tr>";


    $(function () {
        $.ajax({
            url: "http://localhost:9000/seckill/seckillGood/query",
            type: "get",
            xhrFields: {withCredentials: true}, //启用cookie
            success:function (data) {
                if(data.code==200){
                    //填充表格中的数据
                    render(data.data);
                }else{
                    layer.msg(data.msg)
                }
            }
        });
    });


    function render(goodlist) {
        for(var i=0;i<goodlist.length;i++){
            $("#goodlist").append(template.format(goodlist[i]));
        }

    }
    
</script>
</body>
</html>

4 商品查询

由于在前端页面展示的信息来自不同的两张表,因此需要运用远程调用:

    1. 在单表查询 数据 t_seckill_good 数据 秒杀的商品 列表 SeckillGoodList
    1. 获取 good_id 集合 ids[1,2]
    1. 远程调用 good-server 传递参数 [1,2] 在商品表中查询 t_goods 数据 GoodList

4.1 创建实体类

1 创建商品类

@Data
public class Good implements Serializable {

    private Long id;
    private String goodName;
    private String  goodTitle;
    private String  goodImg;
    private String goodDetail;
    private BigDecimal goodPrice;
    private Integer  goodStock;
}

2 创建秒杀类

@Data
public class SeckillGoods implements Serializable {

    private Long id;
    private Long goodId;
    private BigDecimal seckillPrice;
    private Integer stockCount;
    //时间的问题后续得处理 ----
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date startDate;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date endDate;
}

3 创建前端封装类(对应前端页面需要展示的数据)

@Data
public class SeckillGoodVo extends SeckillGood implements Serializable{

    private String goodName;
    private String  goodTitle;
    private String  goodImg;
    private String goodDetail;
    private BigDecimal goodPrice;
}

4.2 实现远程调用(通过远程调用传递的ids来查找商品信息)

1 创建断路器

public class GoodFeignHystrix implements GoodFeignApi {
    @Override
    public Result<List<Good>> queryByIds(List<Long> ids) {
        return null;
    }
}

2 创建远程调用接口

@FeignClient(name = "good-server", fallbackFactory = GoodFeignHystrix.class)
public interface GoodFeignApi {

    @RequestMapping("/queryByIds")
    public Result<List<Good>> queryByIds(@RequestParam("ids") List<Long> ids);

}

3 创建Mapper接口

@Mapper
public interface GoodMapper {

    /**
     * 根据id查询商品信息
     * @param ids
     * @return
     */
    @SelectProvider(type = GoodMapperSQLProvider.class, method = "queryByIds")
    public List<Good> queryByIds(@Param("ids") List<Long> ids);

    /**
     * 由于没有mapper的配置文件,不能使用foreach标签,因此在这里实现SQL的循环
     */
    class GoodMapperSQLProvider{
        /**
         * select * from t_goods where id in (x, x, x,....),将ids循环遍历到()内
         * @param ids
         * @return
         */
        public String queryByIds(@Param("ids") List<Long> ids){
            StringBuilder sb = new StringBuilder();

            sb.append("select * from t_goods ");
            if (ids != null || ids.size() > 0){

                sb.append(" where id in (");
                for (int i = 0; i < ids.size(); i++) {
                    if (i != 0){
                        sb.append(",");
                    }
                    sb.append(ids.get(i));
                }

                sb.append(")");
            }

            return sb.toString();
        }
    }
}

4 创建service业务逻辑接口及其实现类


service业务逻辑接口

public interface GoodService {

    /**
     * 根据id查询商品信息
     * @param ids
     * @return
     */
    public List<Good> queryByIds(List<Long> ids);
}

实现类

@Service
public class GoodServiceImpl implements GoodService {

    @Autowired
    private GoodMapper goodMapper;

    @Override
    public List<Good> queryByIds(List<Long> ids) {

        if (ids == null || ids.size() == 0){
            return Collections.emptyList();
        }

        return goodMapper.queryByIds(ids);
    }
}

5 创建controller层

@RestController
public class GoodFeignClient implements GoodFeignApi {

    @Autowired
    private GoodService goodService;
    @Override
    public Result<List<Good>> queryByIds(List<Long> ids) {
        List<Good> goodlist = goodService.queryByIds(ids);
        return Result.success(goodlist);
    }
}

4.3 数据聚合(把商品信息和秒杀信息聚合为前端页面所需的类)

1 创建秒杀的CodeMsg

public class SeckillCodeMsg extends CodeMsg {


    public SeckillCodeMsg() {
    }

    public SeckillCodeMsg(Integer code, String msg) {
        super(code, msg);
    }


    public static  final SeckillCodeMsg PRODUCT_SERVER_ERROR= new SeckillCodeMsg(500010,"商品微服务繁忙");
    public static  final SeckillCodeMsg LOGIN_TIMEOUT= new SeckillCodeMsg(500011,"登录信息过期了");
    public static  final SeckillCodeMsg OP_ERROR= new SeckillCodeMsg(500012,"非法操作");

}

2 创建Mapper接口

@Mapper
public interface SeckillGoodMapper {

    @Select("SELECT * FROM t_seckill_goods")
    public List<SeckillGood> query();
}

3 创建service业务逻辑接口及其实现类


service业务逻辑接口

public interface SeckillGoodService {

    /**
     * 查询商品数据
     * @return
     */
    public List<SeckillGoodVo> query();
}

实现类

@Service
public class SeckillGoodServiceImpl implements SeckillGoodService {

    @Autowired
    private SeckillGoodMapper seckillGoodMapper;

    @Autowired
    private GoodFeignApi goodFeignApi;

    @Override
    public List<SeckillGoodVo> query() {
        //1. 单表查询 数据 t_seckill_good 数据 秒杀的商品 列表  SeckillGoodList
        List<SeckillGood> seckillGoodList = seckillGoodMapper.query();
        //2. 获取 good_id 集合 ids[1,2]

        //3  远程调用 good-server   传递参数 [1,2] 在商品表中查询   t_goods 数据 GoodList
        List<SeckillGoodVo> seckillGoodVoList = getSeckillGoodVos(seckillGoodList);


        return seckillGoodVoList;
    }

    /**
     * 获取秒杀商品列表
     *
     * @param seckillGoodList
     * @return
     */
    private List<SeckillGoodVo> getSeckillGoodVos(List<SeckillGood> seckillGoodList) {
        //利用set集合来进行数据去重
        Set<Long> idSet = new HashSet<>();
        for (SeckillGood seckillGood : seckillGoodList) {
            //去除重复的goodid
            idSet.add(seckillGood.getGoodId());
        }

        List<Long> ids = new ArrayList<>(idSet);
        //远程调用获取商品信息
        Result<List<Good>> result = goodFeignApi.queryByIds(ids);

        //远程调用失败
        if (result == null || result.hasError()) {
            throw new BusinessException(SeckillCodeMsg.PRODUCT_SERVER_ERROR);
        }

        //远程调用成功
        List<Good> goodList = result.getData();

        //获取商品信息存到Map中
        Map<Long, Good> goodMap = new HashMap<>();
        for (Good good : goodList) {
            goodMap.put(good.getId(), good);
        }

        //将商品信息和秒杀信息聚合
        List<SeckillGoodVo> seckillGoodVoList = new ArrayList<>();

        for (SeckillGood seckillGood : seckillGoodList) {
            //获取商品
            Good good = goodMap.get(seckillGood.getGoodId());

            //聚合
            SeckillGoodVo vo = new SeckillGoodVo();
            vo.setGoodDetail(good.getGoodDetail());
            vo.setGoodImg(good.getGoodImg());
            vo.setGoodName(good.getGoodName());
            vo.setGoodPrice(good.getGoodPrice());
            vo.setGoodTitle(good.getGoodTitle());
            //秒杀的结束时间
            vo.setEndDate(seckillGood.getEndDate());
            vo.setGoodId(good.getId());
            vo.setId(seckillGood.getId());//场次id
            vo.setStartDate(seckillGood.getStartDate());//秒杀开始时间
            vo.setStockCount(seckillGood.getStockCount());//秒杀商品的数量
            vo.setSeckillPrice(seckillGood.getSeckillPrice());//秒杀价格
            //添加到集合中
            seckillGoodVoList.add(vo);

        }
        return seckillGoodVoList;
    }
}

4 创建controller层

@RestController
@RequestMapping("/seckillGood")
public class SeckillGoodController {

    @Autowired
    private SeckillGoodService seckillGoodService;

    @RequestMapping("/query")
    public Result query(){

        List<SeckillGoodVo> seckillGoodVoList = seckillGoodService.query();
        return Result.success(seckillGoodVoList);
    }
}

4.4 登录测试

  • 15
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值