天猫项目(8)产品图片管理

这里实现的是每一个产品下的图片的管理,图片分为单个图片与详情图片两部分

先放一下实现的功能的界面

其实我自己也完成了,但是懒嘛,就放了教程中的,理解一下哈

1.pojo


@Entity
@Table(name = "productimage")
@JsonIgnoreProperties({
        "handler","hibernateLazyInitializer"
})
public class ProductImage {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @ManyToOne
    @JoinColumn(name = "pid")
    @JsonBackReference
    private Product product;

    private String type;

   
}

这里还是和之前的多对一一样的,引入引用的product类

这里其实还要对product的pojo进行改造

加入一个属性Image

 //新加入的,产品图片管理
    @Transient
    private ProductImage firstProductImage;

正如先前所说@Transient注解说明这个属性是不会自动映射的,然后在产品的Service中也会增加其set方法,具体为啥要加这个不映射的东东,后面有机会再去思考

2.dao

public interface ProductImageDAO extends JpaRepository<ProductImage,Integer>{

    public List<ProductImage> findByProductAndTypeOrderByIdDesc(Product product,String type);
}

给出了一个find方法的实现,这里的方法意义后续再补充,jpa中的自动生成的方法的命名,后续应该会补充在一个专门的博客里面,这里先挖一个坑

这里其实用到的是条件查询哈,刚开始写文章,一些名词还不太熟悉,具体的可以参考这个链接中的步骤六中的,这里的OrderBy其实就是对结果进行id倒排序的意思

3.service

@Service
public class ProductImageService {

    public static final String type_single = "single";
    public static final String type_detail = "detail";

    @Autowired
    ProductImageDAO productImageDAO;

    @Autowired
    ProductService productService;

    public void add(ProductImage bean) {
        productImageDAO.save(bean);
    }

    public void delete(int id) {
        productImageDAO.delete(id);
    }

    public ProductImage get(int id){
        return productImageDAO.findOne(id);
    }

    public List<ProductImage> listSingleProductImages(Product product) {
        return productImageDAO.findByProductAndTypeOrderByIdDesc(product,type_single);
    }

    public List<ProductImage> listDetailProductImages(Product product) {
        return productImageDAO.findByProductAndTypeOrderByIdDesc(product,type_detail);
    }

    public void setFirstProductImage(Product product) {
        List<ProductImage> singleImages = listSingleProductImages(product);
        if (!singleImages.isEmpty()) {
            product.setFirstProductImage(singleImages.get(0));
        }
        else {
            product.setFirstProductImage(new ProductImage());
        }
    }

    public void setFirstProductImages(List<Product> products) {
        for (Product product : products) {
            setFirstProductImage(product);
        }
    }
}

加入两个final属性,single和detail,用来区分两种图片,这里只需要增删查的逻辑,所以只给出了这三种方法

这里主要给出来了两个list方法,分别是针对两种图片的,然后由于产品图片可能还没有设置,就要去访问,所以增加了两个方法,在后续的controller中会去调用

4.controller


@RestController
public class ProductImageController {

    @Autowired
    ProductImageService productImageService;

    @Autowired
    ProductService productService;

//原来的代码里面有,但是经实验没有用到CategoryService
   // @Autowired
    //CategoryService categoryService;

    @GetMapping("/products/{pid}/productImages")
    public List<ProductImage> list(@RequestParam("type") String type,@PathVariable("pid") int pid){
        Product product = productService.get(pid);

        if (ProductImageService.type_single.equals(type)) {
            List<ProductImage> singles = productImageService.listSingleProductImages(product);
            return singles;
        } else if (ProductImageService.type_detail.equals(type)) {
            List<ProductImage> details = productImageService.listDetailProductImages(product);
            return details;
        } else {
            return new ArrayList<>();
        }
    }

    @PostMapping("/productImages")
    public Object add(@RequestParam("pid") int pid, @RequestParam("type") String type,
                      MultipartFile image, HttpServletRequest request) {
        ProductImage bean = new ProductImage();
        Product product = productService.get(pid);
        bean.setProduct(product);
        bean.setType(type);

        productImageService.add(bean);
        String folder = "img/";
        if (ProductImageService.type_single.equals(bean.getType())) {
            folder += "productSingle";
        } else {
            folder += "productDetail";
        }
        File imageFolder = new File(request.getServletContext().getRealPath(folder));
        File file = new File(imageFolder, bean.getId() + ".jpg");
        String fileName = file.getName();
        if (!file.getParentFile().exists())
            file.getParentFile().mkdirs();
        try {
            image.transferTo(file);
            BufferedImage img = ImageUtil.change2jpg(file);
            ImageIO.write(img, "jpg", file);
        } catch (IOException e) {
            e.printStackTrace();
        }

        if (ProductImageService.type_single.equals(bean.getType())){
            String imageFolder_small = request.getServletContext().getRealPath("img/productSingle_small");
            String imageFolder_middle = request.getServletContext().getRealPath("img/productSingle_middle");
            File f_small = new File(imageFolder_small, fileName);
            File f_middle = new File(imageFolder_middle, fileName);
            f_small.getParentFile().mkdirs();
            f_middle.getParentFile().mkdirs();
            ImageUtil.resizeImage(file, 56, 56, f_small);
            ImageUtil.resizeImage(file, 217, 190, f_middle);
        }

        return bean;
    }

    @DeleteMapping("/productImages/{id}")
    public String delete(@PathVariable("id") int id, HttpServletRequest request) {
        ProductImage bean = productImageService.get(id);
        productImageService.delete(id);

        String folder = "img/";
        if (ProductImageService.type_single.equals(bean.getType()))
            folder += "productSingle";
        else
            folder += "productDetails";

        File imageFolder = new File(request.getServletContext().getRealPath(folder));

        File file = new File(imageFolder,bean.getId()+".jpg");
        String fileName = file.getName();
        file.delete();
        if (ProductImageService.type_single.equals(bean.getType())) {
            String imageFolder_small = request.getServletContext().getRealPath("img/productSingle_small");
            String imageFolder_middle = request.getServletContext().getRealPath("img/productSingle_middle");
            File f_small = new File(imageFolder_small, fileName);
            File f_middle = new File(imageFolder_middle, fileName);
            f_small.delete();
            f_middle.delete();
        }
        return null;
    }
}

这里的list方法哈,其实就是根据传入的pid去查找出当前的product对象,然后再去遍历出来,用到了service中说到的,如果不存在,就去创建这个List

下一个方法add,一开始的操作大家都懂的,初始化bean对象,然后呢,就是对图片的操作,分别把传入的图片放入两个不同的目录下,然后再把图片给resize,分为small和middle

delete就不用说了,删除掉记录和其目录下图片

想到一个问题,这里的对产品的图片的操作的实现流程,为何与分类的图片的流程不太一样,为何这里要先创建出一个List

另外一个问题就是,这里的type属性的设计问题,为了实现分类的图片存储,该如何实现这个业务逻辑

5.listProductImage.html

<script>
    $(function () {
        var pid = getUrlParms("pid");
        var data4Vue = {
            uri: 'productImages',
            singleProductImages: [],
            detailProductImages: [],
            product: '',
            category: '',
            singleFile: '',
            detailFile: ''
        };

        //ViewModel
        var vue = new Vue({
            el: '#workingArea',
            data: data4Vue,
            mounted:function () {
                //mounted 表示这个Vue被加载成功了
                this.listSingles();
                this.listDetails();
                this.getProduct(pid);
            },
            methods: {
                getProduct: function (pid) {
                    var url = "products/" + pid;
                    axios.get(url).then(function (response) {
                        vue.product = response.data;
                        vue.category = vue.product.category;
                    })
                },
                listSingles: function () {
                    var url = "products/"+ pid + "/" + this.uri + "?type=single";
                    axios.get(url).then(function (response) {
                        vue.singleProductImages = response.data;
                    });
                },
                listDetails: function () {
                    var url = "products/"+ pid + "/" + this.uri + "?type=detail";
                    axios.get(url).then(function (response) {
                        vue.detailProductImages = response.data;
                    });
                },
                addSingle: function () {
                    if (!checkEmpty(this.singleFile, "单个产品图片"))
                        return;

                    var url = this.uri + "?type=single&pid="+pid;
                    var formData = new FormData();
                    formData.append("image", this.singleFile);
                    axios.post(url, formData).then(function (response) {
                        vue.listSingles();
                        $('#singlePic').val('');
                        vue.singleFile = null;
                    });
                },
                addDetail: function () {
                    if (!checkEmpty(this.detailFile, "详情产品图片"))
                        return;

                    var url = this.uri + "?type=detail&pid="+pid;
                    var formData = new FormData();
                    formData.append("image", this.detailFile);
                    axios.post(url, formData).then(function (response) {
                        vue.listDetails();
                        $('#detailPic').val('');
                        vue.detail = null;
                    });
                },
                //delete是保留字
                deleteBean: function (id) {
                    //这里其实会出现一个确认删除的提示框
                    if (!checkDeleteLink())
                        return;
                    //url规范,说实话这里的接口其实是和controller映射一致的吧
                    var url = this.uri + "/" + id;
                    axios.delete(url).then(function (response) {
                        vue.listSingles();
                        vue.listDetails();
                    });
                },
                getSingleFile: function (event) {
                    this.singleFile = event.target.files[0];
                },
                getDetailFile: function (event) {
                    this.detailFile = event.target.files[0];
                }
            }
        });
    });
</script>

其实根据现在的理解,vue的data中,只是给出了,需要用到的数据名,绑定的过程其实好像是自动完成的,这个过程是下一步对vue理解的重点,自己对vue与html中对象的绑定好像有点感觉了

这里的event.target.files[]搞得我有点懵,这里是如何实现get到传入的文件的呢,需要接着补这方面的知识

<input id="singlePic" type="file" @change="getSingleFile($event)" name="image" />

这里的add操作需要两个param,这一点在controller中也很清楚了,两个param用&分隔

<div id="workingArea" >
    <ol class="breadcrumb">
        <li><a href="admin_category_list">所有分类</a></li>
        <li><a :href="'admin_product_list?cid='+category.id">{{category.name}}</a></li>
        <li class="active">{{product.name}}</li>
        <li class="active">产品图片管理</li>
    </ol>

    <table class="addPictureTable" align="center">
        <tr>
            <td class="addPictureTableTD">
                <div>
                    <div class="panel panel-warning addPictureDiv">
                        <div class="panel-heading">新增产品<b class="text-primary"> 单个 </b>图片</div>
                        <div class="panel-body">
                            <table class="addTable">
                                <tr>
                                    <td>请选择本地图片 尺寸400X400 为佳</td>
                                </tr>
                                <tr>
                                    <td>
                                        <input id="singlePic" type="file" @change="getSingleFile($event)" name="image" />
                                    </td>
                                </tr>
                                <tr class="submitTR">
                                    <td align="center">
                                        <button type="submit" @click="addSingle" class="btn btn-success">提 交</button>
                                    </td>
                                </tr>
                            </table>
                        </div>
                    </div>
                    <table class="table table-striped table-bordered table-hover  table-condensed">
                        <thead>
                        <tr class="success">
                            <th>ID</th>
                            <th>产品单个图片缩略图</th>
                            <th>删除</th>
                        </tr>
                        </thead>
                        <tbody>
                        <tr v-for="pi in singleProductImages">
                            <td>{{pi.id}}</td>
                            <td>
                                <a title="点击查看原图" :href="'img/productSingle/'+pi.id+'.jpg'"><img height="50px" :src="'img/productSingle/'+pi.id+'.jpg'"></a>
                            </td>
                            <td><a href="#nowhere" @click="deleteBean(pi.id)"><span class="glyphicon glyphicon-trash"></span></a></td>

                        </tr>
                        </tbody>
                    </table>

                </div>
            </td>
            <td class="addPictureTableTD">
                <div>

                    <div class="panel panel-warning addPictureDiv">
                        <div class="panel-heading">新增产品<b class="text-primary"> 详情 </b>图片</div>
                        <div class="panel-body">
                            <table class="addTable">
                                <tr>
                                    <td>请选择本地图片 宽度790  为佳</td>
                                </tr>
                                <tr>
                                    <td>
                                        <input id="detailPic" type="file" @change="getDetailFile($event)" name="image" />
                                    </td>
                                </tr>
                                <tr class="submitTR">
                                    <td align="center">
                                        <button type="submit" @click="addDetail" class="btn btn-success">提 交</button>
                                    </td>
                                </tr>
                            </table>

                        </div>
                    </div>
                    <table class="table table-striped table-bordered table-hover  table-condensed">
                        <thead>
                        <tr class="success">
                            <th>ID</th>
                            <th>产品详情图片缩略图</th>
                            <th>删除</th>
                        </tr>
                        </thead>
                        <tbody>
                        <tr v-for="pi in detailProductImages">
                            <td>{{pi.id}}</td>
                            <td>
                                <a title="点击查看原图" :href="'img/productDetail/'+pi.id+'.jpg'"><img height="50px" :src="'img/productDetail/'+pi.id+'.jpg'"></a>
                            </td>
                            <td><a href="#nowhere" @click="deleteBean(pi.id)"><span class="glyphicon glyphicon-trash"></span></a></td>

                        </tr>
                        </tbody>
                    </table>
                </div>
            </td>
        </tr>
    </table>
</div>

再给出html部分的代码

这里一个有点意思的是查看原图的一个操作,直接跳转到了,图片所在的目录

路还很长,继续努力

谢谢观看

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页