乐优商城学习笔记 Day04 (非教程)

乐优商城学习Day04:

注意:此次代码都是在第三天的基础上

第三天的链接如下:

https://blog.csdn.net/zcylxzyh/article/details/98210600


此次笔记内容主要为:
1.把图片放入虚拟机
2.查询规格组和查询规格参数的实现
3.实现SPU

下面开始第四天的学习:


1.把图片放进虚拟机:

在这里插入图片描述
创建static文件夹
在这里插入图片描述
在这里插入图片描述
进入static,把图片放入
在这里插入图片描述
然后去命令台解压:
在这里插入图片描述
解压
在这里插入图片描述
然后删除安装包:

在这里插入图片描述
进入images
在这里插入图片描述
修改nginx配置:
在这里插入图片描述
至此结束。

2.查询规格组和查询规格参数的实现

先写实体类:
在ly-item-interface中如下创建实体类SpecGroup(规格组的实体类),SpecParam(规格参数的实体类)
在这里插入图片描述
SpecGroup代码如下:

package com.leyou.item.pojo;

import lombok.Data;
import tk.mybatis.mapper.annotation.KeySql;

import javax.persistence.Id;
import javax.persistence.Table;

@Data
@Table(name = "tb_spec_group")
public class SpecGroup {
    
    

    @Id
    @KeySql(useGeneratedKeys = true)
    private Long id;
    private Long cid;
    private String name;
}

SpecParam代码如下:

package com.leyou.item.pojo;

import lombok.Data;
import tk.mybatis.mapper.annotation.KeySql;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;

@Table(name = "tb_spec_param")
@Data
public class SpecParam {
    
    
    @Id
    @KeySql(useGeneratedKeys = true)
    private Long id;
    private Long cid;
    private Long groupId;
    private String name;
    @Column(name = "`numeric`")
    private Boolean numeric;
    private String unit;
    private Boolean generic;
    private Boolean searching;
    private String segments;

}

然后在写mapper
在ly-item-service中如下位置创建SpecGroupMapper,SpecParamMapper 接口

在这里插入图片描述
SpecGroupMapper代码如下:

package com.leyou.item.mapper;

import com.leyou.item.pojo.SpecGroup;
import tk.mybatis.mapper.common.Mapper;

public interface SpecGroupMapper extends Mapper<SpecGroup>{
    
    
}

SpecParamMapper 代码如下

package com.leyou.item.mapper;

import com.leyou.item.pojo.SpecParam;
import tk.mybatis.mapper.common.Mapper;

public interface SpecParamMapper extends Mapper<SpecParam> {
    
    
}

在写controller和service

在这里,我们把查询规格参数和查询规格组的功能实现放到一个controller、service中:
在这里插入图片描述
SpecificationService代码如下:

package com.leyou.item.service;

import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.item.mapper.SpecGroupMapper;
import com.leyou.item.mapper.SpecParamMapper;
import com.leyou.item.pojo.SpecGroup;
import com.leyou.item.pojo.SpecParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;

@Service
public class SpecificationService {
    
    
    @Autowired
    private SpecGroupMapper groupMapper;

    @Autowired
    private SpecParamMapper paramMapper;

    public List<SpecGroup> queryGroupByCid(Long cid) {
    
    
        //查询条件
        SpecGroup group = new SpecGroup();
        group.setCid(cid);
        //开始查询
        List<SpecGroup> list = groupMapper.select(group);
        if(CollectionUtils.isEmpty(list)){
    
    
            //没查到
            throw new LyException(ExceptionEnum.SPEC_GROUP_NOT_FOUND);
        }
        return list;

    }

    public List<SpecParam> queryParamByGid(Long gid) {
    
    

        SpecParam param = new SpecParam();
        param.setGroupId(gid);
        List<SpecParam> list = paramMapper.select(param);
        if(CollectionUtils.isEmpty(list)){
    
    
            //没查到
            throw new LyException(ExceptionEnum.SPEC_PARAM_NOT_FOUND);
        }
        return list;
    }
}

SpecificationController代码如下:

package com.leyou.item.web;


import com.leyou.item.pojo.SpecGroup;
import com.leyou.item.pojo.SpecParam;
import com.leyou.item.service.SpecificationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("spec")
public class SpecificationController {
    
    

    @Autowired
    private SpecificationService specService;
    /*
    * 根据分类id查询规格组
    *
    *  */
    @GetMapping("groups/{cid}")
    public ResponseEntity<List<SpecGroup>> queryGroupByCid(@PathVariable("cid")Long cid){
    
    
        return ResponseEntity.ok(specService.queryGroupByCid(cid));
    }

    //根据组id查询参数
    @GetMapping("params")
    public ResponseEntity<List<SpecParam>> queryParamByGid(@RequestParam("gid")Long gid){
    
    
        return ResponseEntity.ok(specService.queryParamByGid(gid));
    }
}

结果:
规格组:
在这里插入图片描述
规格参数:
在这里插入图片描述
在这里插入图片描述
至此,第二部分结束。

3.实现SPU

SPU:Standard Product Unit (标准产品单位) ,一组具有共同属性的商品集

SKU:Stock Keeping Unit(库存量单位),SPU商品集因具体特性不同而细分的每个商品

在这里插入图片描述

  • 本页的 华为Mate10 就是一个商品集(SPU)
  • 因为颜色、内存等不同,而细分出不同的Mate10,如亮黑色128G版。(SKU)

可以看出:

  • SPU是一个抽象的商品集概念,为了方便后台的管理。
  • SKU才是具体要销售的商品,每一个SKU的价格、库存可能会不一样,用户购买的是SKU而不是SPU

下面实现SPU:

首先引入SPU的两个实体类Spu,SpuDetail(Spu的详情),我们做了表的垂直拆分,将SPU的详情放到了另一张表:tb_spu_detail因此有两个实体类:
在这里插入图片描述
Spu代码如下:

package com.leyou.item.pojo;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import tk.mybatis.mapper.annotation.KeySql;

import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
import java.util.Date;

@Table(name = "tb_spu")
@Data
public class Spu {
    
    
    @Id
    @KeySql(useGeneratedKeys = true)
    private Long id;
    private Long brandId;
    private Long cid1;//1级类目
    private Long cid2;//2级类目
    private Long cid3;//3级类目
    private String title;//标题
    private String subTitle;//子标题
    private Boolean saleable;//是否上架

    @JsonIgnore
    private Boolean valid;//是否有效,逻辑删除用
    private Date createTime;//创建时间

    @JsonIgnore //返回到页面时忽略这个字段
    private Date lastUpdateTime;//最后修改时间

    @Transient //因为不是数据库字段所以加上这个注解,不是bean包下的
    private String cname;
    @Transient
    private String bname;
}

SpuDetail代码如下:

package com.leyou.item.pojo;

import lombok.Data;

import javax.persistence.Id;
import javax.persistence.Table;

@Table(name = "tb_spu_detail")
@Data
public class SpuDetail {
    
    
    @Id
    private Long spuId;
    private String description;
    private String specialSpec;
    private String genericSpec;
    private String packingList;
    private String afterService;

}

写SpuMapper和SpuDetailMapper
在这里插入图片描述
SpuMapper代码如下:

package com.leyou.item.mapper;

import com.leyou.item.pojo.Spu;
import tk.mybatis.mapper.common.Mapper;

public interface SpuMapper extends Mapper<Spu> {
    
    
}

SpuDetailMapper代码如下:

package com.leyou.item.mapper;

import com.leyou.item.pojo.SpuDetail;
import tk.mybatis.mapper.common.Mapper;

public interface SpuDetailMapper extends Mapper<SpuDetail> {
    
    
}

然后写Service,这里不管是SPU,SKU(明天学习)还是SPUDetail…都用一个Service:GoodsService
在这里插入图片描述
GoodsService代码如下:

package com.leyou.item.service;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.common.vo.PageResult;
import com.leyou.item.mapper.SpuDetailMapper;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.pojo.Category;
import com.leyou.item.pojo.Spu;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class GoodsService {
    
    
    @Autowired
    private SpuMapper spuMapper;

    @Autowired
    private SpuDetailMapper detailMapper;

    @Autowired CategoryService categoryService;

    @Autowired BrandService brandService;

    public PageResult<Spu> querySpuByPage(Integer page, Integer rows, Boolean saleable, String key) {
    
    

        //分页
        PageHelper.startPage(page,rows);
        //过滤
        Example example = new Example(Spu.class);
        //搜索字段过滤
        Example.Criteria criteria = example.createCriteria();

        if(StringUtils.isNotBlank(key)){
    
    
            criteria.andLike("title","%"+key+"%");
        }
        //上下架过滤
        if (saleable != null){
    
    
            criteria.andEqualTo("saleable",saleable);
        }
        //默认排序
        example.setOrderByClause("last_update_time DESC");

        //查询
        List<Spu> spus = spuMapper.selectByExample(example);
        //判断
        if(CollectionUtils.isEmpty(spus)){
    
    
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        //解析分类和品牌的名称
        loadCategoryAndBrandName(spus);

        //解析分页结果
        PageInfo<Spu> info = new PageInfo<>(spus);
        return new PageResult<>(info.getTotal(),spus);
    }

    private void loadCategoryAndBrandName(List<Spu> spus) {
    
    
        for(Spu spu : spus){
    
    
            //处理分类名称
            List<String> names = categoryService.queryByIds(Arrays.asList(spu.getCid1(), spu.getCid2(), spu.getCid3()))
                    .stream().map(Category::getName).collect(Collectors.toList());
            spu.setCname(StringUtils.join(names,"/"));

            //处理品牌名称
            spu.setBname(brandService.queryById(spu.getBrandId()).getName());
        }
    }
}

然后写Controller,这里不管是SPU,SKU(明天学习)还是SPUDetail…都用一个Controller:GoodsController
在这里插入图片描述
GoodsController代码如下:

package com.leyou.item.web;

import com.leyou.common.vo.PageResult;
import com.leyou.item.pojo.Spu;
import com.leyou.item.service.GoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GoodsController {
    
    

    @Autowired
    private GoodsService goodsService;
    @GetMapping("/spu/page")
    public ResponseEntity<PageResult<Spu>> querySpuByPage(
            @RequestParam(value = "page",defaultValue = "1") Integer page,
            @RequestParam(value = "rows",defaultValue = "5") Integer rows,
            @RequestParam(value = "saleable",required = false) Boolean saleable,
            @RequestParam(value = "key",required = false) String key
    ){
    
    
        return ResponseEntity.ok(goodsService.querySpuByPage(page,rows,saleable,key));
    }
}

今天的代码实现了新的功能,需要修改Category的Service和Mapper、Brand的Service和Mapper,枚举类,ly-item-interface的pom.xml:

Category的Service和Mapper:
Mapper

package com.leyou.item.mapper;

import com.leyou.item.pojo.Category;
import tk.mybatis.mapper.additional.idlist.IdListMapper;
import tk.mybatis.mapper.common.Mapper;

public interface CategoryMapper extends Mapper<Category>,IdListMapper<Category,Long>{
    
    
}

Service

package com.leyou.item.service;

import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.item.pojo.Category;
import com.leyou.item.mapper.CategoryMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;

@Service
public class CategoryService {
    
    
    @Autowired
    private CategoryMapper categoryMapper;

    public List<Category> queryCategoryListByPid(Long pid) {
    
    
        //查询条件,mapper会把对象中的非空属性作为查询条件
        Category t = new Category();
        t.setParentId(pid);
        List<Category> list = categoryMapper.select(t);
        //判断结果
        if (CollectionUtils.isEmpty(list)) {
    
    
            //返回404
            throw new LyException(ExceptionEnum.CATEGORY_NOT_FOND);
        }
        return list;
    }

    public List<Category> queryByIds(List<Long> ids){
    
    
        List<Category> list = categoryMapper.selectByIdList(ids);
        if (CollectionUtils.isEmpty(list)) {
    
    
            //返回404
            throw new LyException(ExceptionEnum.CATEGORY_NOT_FOND);
        }
        return list;
    }
}

Brand的Service和Mapper
Mapper

package com.leyou.item.mapper;

        import com.leyou.item.pojo.Brand;
        import org.apache.ibatis.annotations.Insert;
        import org.apache.ibatis.annotations.Param;
        import tk.mybatis.mapper.common.Mapper;

public interface BrandMapper extends Mapper<Brand> {
    
    

    @Insert("INSERT INTO tb_category_brand (category_id,brand_id) VALUES (#{cid},#{bid})")
    int insertCategoryBrand(@Param("cid") Long cid ,@Param("bid") Long bid);
}

Service

package com.leyou.item.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.common.vo.PageResult;
import com.leyou.item.mapper.BrandMapper;
import com.leyou.item.pojo.Brand;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.List;

@Service
public class BrandService {
    
    
    @Autowired
    private BrandMapper brandMapper;
//sortBy 根据什么排序,比如id
    public PageResult<Brand> queryBrandByPage(Integer page, Integer rows, String sortBy, Boolean desc, String key) {
    
    
        //分页,使用分页助手,在查询语句前调用这个方法就能实现分页,这里是page,rows
        PageHelper.startPage(page,rows);//第一个参数:当前页,第二个参数:每页大小

        //Example需要一个实体类(字节码),让他知道去哪个表查
        Example example = new Example(Brand.class);

        //条件过滤,查询用的,这里是key
        if (StringUtils.isNotBlank(key)){
    
    
            //过滤条件,也就是sql语句
            /*
            * WHERE 'name' LIKE "%X%" OR letter =='X'
            * ORDER BY id DESC
            * */
            //key.toUpperCase()转大写
            example.createCriteria().orLike("name","%"+key+"%")
                    .orEqualTo("letter",key.toUpperCase());
        }
        //排序
        if(StringUtils.isNotBlank(sortBy)){
    
    
            String orderByClause = sortBy+ (desc ? "DESC":"ASC");
            example.setOrderByClause(orderByClause);
        }
        //查询
        List<Brand> list = brandMapper.selectByExample(example);
        //如果为空,证明没查到
        if(CollectionUtils.isEmpty(list)){
    
    
            throw new LyException(ExceptionEnum.BRAND_NOT_FOUND);
        }
        //解析分页结果
        PageInfo<Brand> info = new PageInfo<>(list);
        //返回总条数和list
        return new PageResult<>(info.getTotal(),list);
    }

    //新增,因为复杂需要加上事务注解
    @Transactional
    public void saveBrand(Brand brand, List<Long> cids) {
    
    
        //新增品牌
        brand.setId(null);
        int count = brandMapper.insert(brand);
        if(count!=1){
    
    
            throw new LyException(ExceptionEnum.BRAND_SAVE_ERROR);
        }
        //新增中间表
        for (Long cid : cids) {
    
    
            count=brandMapper.insertCategoryBrand(cid,brand.getId());
            if(count != 1){
    
    
                throw new LyException(ExceptionEnum.BRAND_SAVE_ERROR);
            }
        }

    }
    public Brand queryById(Long id){
    
    
        Brand brand = brandMapper.selectByPrimaryKey(id);
        if(brand ==null){
    
    
            throw new LyException(ExceptionEnum.BRAND_NOT_FOUND);
        }
        return brand;
    }
}



枚举类:

package com.leyou.common.enums;

        import lombok.AllArgsConstructor;
        import lombok.Getter;
        import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
@AllArgsConstructor
//枚举是指只能有固定实例个数的类
public enum ExceptionEnum {
    
    
    PRICE_CANNOT_BE_NULL(400,"价格不能为空!"),
    CATEGORY_NOT_FOND(404,"商品分类没查到"),
    BRAND_NOT_FOUND(404,"品牌不存在"),
    BRAND_SAVE_ERROR(500,"新增品牌失败"),
    UPLOAD_FILE_ERROR(500,"文件上传失败"),
    INVALID_FILE_TYPE(400,"无效的文件类型"),
    SPEC_GROUP_NOT_FOUND(404,"商品规格组不存在"),
    SPEC_PARAM_NOT_FOUND(404,"商品规格参数不存在"),
    GOODS_NOT_FOUND(404,"商品不存在"),
    ;
    private  int code ;
    private  String msg ;

}

ly-item-interface的pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>ly-item</artifactId>
        <groupId>com.leyou.service</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.leyou.service</groupId>
    <artifactId>ly-item-interface</artifactId>
<dependencies>
    <dependency>
        <groupId>tk.mybatis</groupId>
        <artifactId>mapper-core</artifactId>
        <version>1.0.4</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.6</version>
    </dependency>
</dependencies>

</project>

结果:
在这里插入图片描述
至此,第三部分结束。

修改后的nginx配置:


#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;
    client_max_body_size 10m;
    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;
        server {
            listen 9001;
            server_name manage.leyou.com;
 
        location / {
        proxy_pass  http://192.168.31.193:9001;   
          }   
        }
	server {
        listen       80;
        server_name  manage.leyou.com;
 
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 
        location / {
			proxy_pass http://192.168.31.193:9001;
			proxy_connect_timeout 600;
			proxy_read_timeout 600;
        }
    }
	server {
        listen       80;
        server_name  api.leyou.com;
 
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		
		location /api/upload {
		    rewrite "^/(.*)$" /zuul/$1;
		}
		
        location / {
			proxy_pass http://192.168.31.193:10010;
			proxy_connect_timeout 600;
			proxy_read_timeout 600;
        }
    }
    server {
        listen       80;
        server_name  image.leyou.com;

    	# 监听域名中带有group的,交给FastDFS模块处理
        location ~/group([0-9])/ {
            ngx_fastdfs_module;
        }

        location / {
            root   /leyou/static/;
            index  index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
        
    }
    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}

至此今天的学习结束。

猜你喜欢

转载自blog.csdn.net/zcylxzyh/article/details/98972565
今日推荐