电商生鲜网站开发(四)——后台开发:商品模块-图片上传/多条件拼接sql

电商生鲜网站开发(四)——后台开发:商品模块-图片上传/多条件拼接sql

增加商品

电商生鲜网站开发(四)——后台开发:商品模块-图片上传/多条件拼接sql

上传图片

更新商品

删除商品

批量上下架

图片上传功能

文件名UUID

通用唯一识别码(Universally Unique Identifier)

防止重名、防止发图

生成规则:日期和时间、MAC地址、HashCode、随机数

配置application.properties

上传文件的路径,根据部署情况自行修改 该值注入到Constan类中
file.upload.dir=/Users/cat/Documents/project/java/online_mall/mall-prepare-static

Constant常量类

package com.learn2333.mall.common;

import com.google.common.collect.Sets;
import com.learn2333.mall.exception.MallException;
import com.learn2333.mall.exception.MallExceptionEnum;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Set;

/**
 * 描述:    常量值
 */
@Component
public class Constant {
    public static final String MALL_USER = "mall_user";
    public static final String SALT = "learn2333";

    public static String FILE_UPLOAD_DIR;

  //因为是static无法直接注入,使用set方法为静态变量注入赋值
    @Value("${file.upload.dir}")
    public void setFileUploadDir(String fileUploadDir) {
        FILE_UPLOAD_DIR = fileUploadDir;
    }

controller

    @PostMapping("/admin/upload/file")
    public ApiRestResponse upload(HttpServletRequest httpServletRequest,
                                  @RequestParam("file") MultipartFile file) {
        String fileName = file.getOriginalFilename();
        String suffixName = fileName.substring(fileName.lastIndexOf("."));  //后缀
        //生成文件名称UUID
        UUID uuid = UUID.randomUUID();
        String newFileName = uuid.toString() + suffixName;
        //创建文件
        File fileDirectory = new File(Constant.FILE_UPLOAD_DIR);
        File destFile = new File(Constant.FILE_UPLOAD_DIR + newFileName);
        //如果文件夹不存在
        if (!fileDirectory.exists()) {
            if (!fileDirectory.mkdir()) {//创建文件夹
                throw new MallException(MallExceptionEnum.MKDIR_FAILED);
            }
        }
        //文件写入
        try {
            file.transferTo(destFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //返回文件地址
        try {
            return ApiRestResponse
                    .success(getHost(new URI(httpServletRequest.getRequestURL() + "")) + "/images/"
                            + newFileName);
        } catch (URISyntaxException e) {
            return ApiRestResponse.error(MallExceptionEnum.UPLOAD_FAILED);
        }
    }

    /**
     * 获取ip和端口号
     * @param uri
     * @return
     */
    private URI getHost(URI uri) {
        URI effectiveURI;
        try {
            effectiveURI = new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(),
                    null, null, null);
        } catch (URISyntaxException e) {
            effectiveURI = null;
        }
        return effectiveURI;
    }

自定义静态资源映射目录

上传图片后回显

配置SpringBootWebMvcConfig

静态资源到本地目录到映射

package com.learn2333.mall.config;

import com.learn2333.mall.common.Constant;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 描述:     配置Swagger地址映射
 */
@Configuration
public class MallWebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
      //图片目录映射
        registry.addResourceHandler("/images/**").addResourceLocations("file:" + Constant.FILE_UPLOAD_DIR);
        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
}

商品批量上下架

MyBatis遍历List

where语句拼接

    <update id="batchUpdateSellStatus">
        update mall_product
        set status = #{sellStatus}
        where id in
        <foreach collection="ids" open="(" close=")" item="id" separator=",">
            #{id}
        </foreach>
    </update>

后台管理员商品列表接口

调用分页PageHelper,跟商品分类模块类似

前台用户商品列表接口

商品列表:搜索功能

使用入参判空、加%通配符、like关键字sql拼接

传入ProductListReq实体

package com.learn2333.mall.model.request;

import java.util.Date;

public class ProductListReq {

    private String keyword;	//关键字
	
    private Integer categoryId;		//分类id

    private String orderBy;		//排序方式
	
  //分页
    private Integer pageNum = 1;

    private Integer pageSize = 10;

get;set;
}

ProjectController

    @ApiOperation("商品列表")
    @GetMapping("product/list")
    public ApiRestResponse list(ProductListReq productListReq){
        PageInfo list = productService.list(productListReq);
        return ApiRestResponse.success(list);
    }

对与这种条件比较多的,拼接麻烦的查询,可以建一个query,也方便后续的修改

ProductListQuery

package com.learn2333.mall.model.query;


import java.util.List;

/**
 * 描述:       查询商品列表的Query
 */
public class ProductListQuery {

    private String keyword;
  //查询一个目录下的商品,不一定是只有当前目录下,还包含子目录,子子目录下的商品;因此之前传入一个目录的id现在还要获取它子目录的所有id
    private List<Integer> categoryIds;

get;set;
}

productServiceImpl

    @Override
    public PageInfo list(ProductListReq productListReq) {
        //构建Query对象
        ProductListQuery productListQuery = new ProductListQuery();

        //搜索处理
        if (!StringUtils.isEmpty(productListReq.getKeyword())) {
            String keyword = new StringBuilder().append("%").append(productListReq.getKeyword())
                    .append("%").toString();
            productListQuery.setKeyword(keyword);
        }

        //目录处理:如果查某个目录下的商品,不仅是需要查出该目录下的,还要把所有子目录的所有商品都查出来,所以要拿到一个目录id的List
        if (productListReq.getCategoryId() != null) {
            //复用之前写过的传入目录id查询子目录方法listCategoryForCustomer
            List<CategoryVO> categoryVOList = categoryService.listCategoryForCustomer(productListReq.getCategoryId());
            //将得到的树形目录结构categoryVOList展开
            ArrayList<Integer> categoryIds = new ArrayList<>();
            categoryIds.add(productListReq.getCategoryId());
            //用下面定义的方法来处理子目录的遍历,
            //通过下面的函数处理就可以将categoryVOList中子目录所有id放入categoryIds,因为传入的是List引用类型
            getCategoryIds(categoryVOList, categoryIds);
            productListQuery.setCategoryIds(categoryIds);
        }

        //排序处理
        String orderBy = productListReq.getOrderBy(); //为了系统安全,不能传入什么就直接按照什么排序,而是要拿到前台传入的排序规则
        if (Constant.ProductListOrderBy.PRICE_ASC_DESC.contains(orderBy)) {	//contains判断是否包含
            PageHelper.startPage(productListReq.getPageNum(), productListReq.getPageSize(), orderBy);
        } else {
            PageHelper.startPage(productListReq.getPageNum(), productListReq.getPageSize());
        }

        List<Product> productList = productMapper.selectList(productListQuery);
        PageInfo pageInfo = new PageInfo(productList);
        return pageInfo;
    }

    //递归遍历子目录
    private void getCategoryIds(List<CategoryVO> categoryVOList, ArrayList<Integer> categoryIds) {
        for (int i = 0; i < categoryVOList.size(); i++) {
            CategoryVO categoryVO = categoryVOList.get(i);
            if (categoryVO != null) {
                categoryIds.add(categoryVO.getId());
                getCategoryIds(categoryVO.getChildCategory(), categoryIds);
            }
        }
    }

常量(排序方式接口)

package com.learn2333.mall.common;

import com.google.common.collect.Sets;
import com.learn2333.mall.exception.MallException;
import com.learn2333.mall.exception.MallExceptionEnum;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Set;

/**
 * 描述:    常量值
 */
@Component
public class Constant {
    public static final String MALL_USER = "mall_user";
    public static final String SALT = "learn2333";

    public static String FILE_UPLOAD_DIR;

    @Value("${file.upload.dir}")
    public void setFileUploadDir(String fileUploadDir) {
        FILE_UPLOAD_DIR = fileUploadDir;
    }

    public interface ProductListOrderBy {
        Set<String> PRICE_ASC_DESC = Sets.newHashSet("price desc", "price asc");

    }

ProductMapper接口

    List<Product> selectList(@Param("query") ProductListQuery query);

ProductMapper

    <select id="selectList" resultMap="BaseResultMap"
            parameterType="com.learn2333.mall.model.query.ProductListQuery">
        select
        <include refid="Base_Column_List"/>
        from mall_product
        <where>
            <if test="query.keyword != null">
                and name like #{query.keyword}
            if>
            <if test="query.categoryIds != null">
                and category_id in
                <foreach collection="query.categoryIds" close=")" item="item" open="(" separator=",">
                    #{item}
                foreach>
            if>
          
            and status = 1
        where>
        order by update_time desc
    select>

排序功能、MyBatis PageHelper、枚举:order by

总结

商品的搜索、排序、目录查询

常见问题:更新和新增不要用一个接口,虽然方便,但是从长期维护角度每一个接口要明确分工;排序的时候要用常量枚举判断,不要直接传入,否则可能被黑客利用,攻击数据库。

版权声明:如无特殊标注,文章均来自网络,本站编辑整理,转载时请以链接形式注明文章出处,请自行分辨。

本文链接:https://www.shbk5.com/dnsj/74581.html