• java学习day69-JT项目07-(商品/详情一对一操作//文件上传)


    商品上架/下架

    业务分析

    当用户点击商品上架下架操作时,应该修改数据库中的状态信息status

    分析:

    1. 下架操作 /item/instock status=2
    2. 上架操作 /item/reshelf status=1

    restFul优化:

    1. 下架操作 /item/updateStatus/2
    2. 上架操作 /item/updateStatus/1

    页面URL分析

    1596590030625

    页面JS

    1596698691970

    实现RestFul调用

    重构页面url地址

    1596698805250

    编辑ItemController

    //商品上下架操作,使用restful风格
    @RequestMapping("/updateStatus/{status}")
    public SysResult updateStatus(Long[] ids,@PathVariable("status") Integer status){
        itemService.updatStatus(ids,status);
        return  SysResult.success();
    }
    

    编辑ItemService

    //利用手写sql实现状态修改
    @Override
    public void updatStatus(Long[] ids, Integer status) {
        itemMapper.updown(ids,status);
    
    }
    
    //利用MP实现状态修改(上下架操作)
    //	@Override
    //	public void updatStatus(Long[] ids, Integer status) {
    //		List<Long> idsList = Arrays.asList(ids);//数组转化为集合
    //		UpdateWrapper<Item> updateWrapper = new UpdateWrapper<>();
    //
    //		updateWrapper.in("id",idsList);
    //		Item item = new Item();
    //		item.setStatus(status);
    //		itemMapper.update(item,updateWrapper);
    //
    //	}
    

    编辑Mapper接口/xml映射文件

    1596699019669

    <update id="updown">
        update  tb_item set status =#{status},updated=now()
        where id in(
        <foreach collection="ids" item="id" separator=",">
            #{id}
        </foreach>
        )
    </update>
    

    富文本编辑器

    富文本编辑器介绍

    ​ KindEditor是一套开源的HTML可视化编辑器,主要用于让用户在网站上获得所见即所得编辑效果,兼容IE、Firefox、Chrome、Safari、Opera等主流浏览器。

    富文本编辑器入门案例

    <%@ page language="java" contentType="text/html; charset=utf-8"
        pageEncoding="utf-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <link href="/js/kindeditor-4.1.10/themes/default/default.css" type="text/css" rel="stylesheet">
    <script type="text/javascript" charset="utf-8" src="/js/kindeditor-4.1.10/kindeditor-all-min.js"></script>
    <script type="text/javascript" charset="utf-8" src="/js/kindeditor-4.1.10/lang/zh_CN.js"></script>
    <script type="text/javascript" charset="utf-8" src="/js/jquery-easyui-1.4.1/jquery.min.js"></script>
    
    <script type="text/javascript">
    	$(function(){
    	    //在指定的为止初始化富文本.
    		KindEditor.ready(function(){
    			KindEditor.create("#editor")
    		})
    	})
    </script>
    </head>
    <body>
    <h1>富文本编辑器</h1>
    
    <textarea style="700px;height:350px" id="editor"></textarea>
    </body>
    </html>
    

    商品表/商品详情表关系

    说明:由于用户查询商品时,首先查询的是商品的主要信息.如果用户对某个商品感兴趣,才会查询商品详情信息.所以采用2张表的形式 展现商品/商品详情.
    思考: 商品信息由商品/详情2部分构成.所有CRUD操作应该同时操作商品详情表.应该实现关联的操作.

    1596699239639

    编辑ItemDesc POJO对象

    package com.jt.pojo;
    /**
     * 构建商品详情的POJO对象
     *
     */
    @TableName("tb_item_desc")
    @Data
    @Accessors(chain = true)
    public class ItemDesc extends BasePojo{
    
        @TableId                //只标识主键即可
        private Long itemId;    //要求与商品表Id保持一致.
        private String itemDesc;    //商品详情信息
    }
    
    
    

    编辑ItemDescMapper

    package com.jt.mapper;
    
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.jt.pojo.ItemDesc;
    //继承接口并且要指定对应的表
    public interface ItemDescMapper extends BaseMapper<ItemDesc> {//对象与表进行绑定
        //如果自己不写sql,则可以省略mapper映射文件的编写
    }
    

    重构后台商品CRUD操作

    重构商品入库操作

    页面参数提交

    说明:在原有的商品新增的基础之上,完成商品详情新增操作.

    1596699383588

    编辑ItemController

    动态接受参数信息 Item/ItemDesc.完成入库修改删除操作

    //需要完成两张表的入库操作
    @RequestMapping("/save")
    public SysResult saveItem(Item item, ItemDesc itemDesc){
        itemService.saveItem(item,itemDesc);
        return  SysResult.success();
    }
    

    编辑ItemService

    //保存商品 完成两张表的入库操作,保证商品的id与商品详情id一致
    //注意事项: 完成数据库数据更新操作时,需要注意数据库事务问题
    @Transactional
    @Override
    public void saveItem(Item item , ItemDesc itemDesc) {
        //保存信息时要记录更改时间
        //		item.setStatus(1).setCreated(new Date()).setUpdated(item.getCreated());
        item.setStatus(1);
        //典型一对一的插入
        itemMapper.insert(item);
        //分析问题: item表的 主键是自增数据库入库之后才会有 主键生成.
        //解决方案:让数据库完成入库之后自动的实现主键的回显。改操作由MP机制动态完成
        //<insert id="xxx" keyProperty="id" useGeneratedKeys="true"></insert>
        itemDesc.setItemId(item.getId());
        itemDescMapper.insert(itemDesc);
    
    }
    

    实现商品详情信息回显

    页面url分析

    说明:检查商品详情展现的url地址路径.

    1596699780262

    页面JS分析

    1596699871372

    编辑ItemController

    说明:根据restFul风格实现商品详情查询.

    /**
    * 	根据商品id查询商品详情信息
    http://localhost:8091/item/query/item/desc/1474391987
    参数:  包含在url中,利用restFul方式动态获取
    * 返回值:  SysResult对象
    *
    */
    @RequestMapping("/query/item/desc/{itemId}")
    public SysResult findItemDescById(@PathVariable("itemId") Long itemId){
    ItemDesc itemDesc= itemService.findItemDescById(itemId);
    //将服务器数据返回页面
    return  SysResult.success(itemDesc);
    }
    

    编辑ItemService

    //根据指定的ID查询商品详情信息
    @Override
    public ItemDesc findItemDescById(Long itemId) {
        ItemDesc itemDesc = itemDescMapper.selectById(itemId);
        return itemDesc;
    }
    

    重构商品修改以及删除操作

    编辑ItemController

    //商品修改操作
    /**
    	 * 完成商品信息修改
    	 * url:http://localhost:8091/item/update
    	 * 参数: 整个商品表单
    	 * 返回值: SysResult对象
    	 */
    @RequestMapping("/update")
    public SysResult updateItem(Item item, ItemDesc itemDesc){
        itemService.updateItem(item,itemDesc);
        return   SysResult.success();
    }
    //删除商品信息 批量删除 (单个删除)
    //springmvc知识点: 可以根据指定的类型动态的实现参数类型的转化 规则: 如果字符串使用","分割,则可以使用数组的形式传参
    /**
    	 * 业务需求: 完成商品删除操作
    	 * url请求地址: /item/delete
    	 * 参数: ids=  id1,id2 串
    	 * 返回值结果:  SysResult对象
    	 * SpringMVC知识点: 可以根据制定的类型动态的实现参数类型的转化.
    	 * 					如果字符串使用","号分隔,则可以使用数组的方式接参.
    	 */
    @RequestMapping("/delete")
    public SysResult deleteItems(Long[] ids){
        itemService.deleteItemsByIds(ids);
        return   SysResult.success();
    }
    

    编辑ItemService

    //修改商品信息
    @Transactional
    @Override
    public void updateItem(Item item , ItemDesc itemDesc) {
        item.setStatus(1);
        //		item.setStatus(1).setCreated(new Date()).setUpdated(item.getCreated());
        itemMapper.updateById(item);//设定主键
        itemDesc.setItemId(item.getId());
        //实现商品详情的更新
        itemDescMapper.updateById(itemDesc);
    }
    //删除商品信息
    @Transactional
    @Override
    public void deleteItemsByIds(Long[] ids) {
        //将数组转化为集合
        //		List<Long> idsList = Arrays.asList(ids);
        //		itemMapper.deleteBatchIds(idsList);
        itemMapper.deleteItems(ids);
        //根据商品id删除商品的详情信息
        itemDescMapper.deleteItemDescByIds(ids);
    }
    

    编辑ItemDescMapper接口

    package com.jt.mapper;
    
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.jt.pojo.ItemDesc;
    //继承接口并且要指定对应的表
    public interface ItemDescMapper extends BaseMapper<ItemDesc> {//对象与表进行绑定
        //如果自己不写sql,则可以省略mapper映射文件的编写
        void deleteItemDescByIds(Long[] ids);
    
    }
    

    编辑ItemDescMapper.xml文件

    <delete id="deleteItemDescByIds">
        delete  from tb_item_desc
        <where>
            item_id in
            <foreach collection="array" item="id" open="(" close=")" separator=",">
                #{id}
            </foreach>
        </where>
    </delete>
    

    商品详情展示

    1596700454135

    文件上传

    文件上传入门案例

    编辑HTML页面

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
    	<h1>实现文件长传</h1>
    	<!--enctype="开启多媒体标签"  -->
    	<form action="http://localhost:8091/file" method="post" 
    	enctype="multipart/form-data">
    		<input name="fileImage" type="file" />
    		<input type="submit" value="提交"/>
    	</form>
    </body>
    </html>
    

    编辑FileController

    package com.jt.controller;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.multipart.MultipartFile;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    
    @RestController
    public class FileController {
    
        /**
         * 完成文件上传的入门案例
         * url地址: http://localhost:8091/file
         * 请求参数: fileImage
         * 返回值:   文件上传成功
         *
         * 利用SpringMVC中提供的工具API,实现文件上传的简化.
         * 记住类型:MultipartFile
         * 实现步骤:
         *      1.接收资源文件
         *      2.准备文件上传目录
         *      3.准备文件上传的全路径   目录/文件名称
         常识: 
    	 * 		1.必须指定文件上传的路径信息   D:JT-SOFTimages文件名称.jpg
    	 * 		2.将字节信息利用outPutStream进行输出操作
    	 * 
    	 * 说明:文件上传默认大小1M=1024*1024   
    	 * 具体参见CommonsFileUploadSupport类
         */
        @RequestMapping("/file")
        public String  file(MultipartFile fileImage){
    
           //2.文件文件上传的目录
            String fileDirPath = "D:/JT-SOFT/images";
            File dirFile = new File(fileDirPath);
            //判断文件目录是否存在
            if(!dirFile.exists()){
                //如果文化间目录没有,则应该新建目录
                dirFile.mkdirs(); //创建多级目录
            }
    
            //3.准备文件上传的全路径.  路径+文件名称
            String fileName = fileImage.getOriginalFilename();  //文件名称.后缀   123.jgp
            File realFile = new File(fileDirPath+"/"+fileName);
            //将字节信息输出到文件中.
            try {
                fileImage.transferTo(realFile); //实现文件上传
                return "文件上传成功!!!";
            } catch (IOException e) {
                e.printStackTrace();
                return "文件上传失败!!!";
            }
    
        }
    }
    

    商品文件上传实现

    富文本编辑器返回值说明

    {“error”:0,“url”:“图片的保存路径”,“width”:图片的宽度,“height”:图片的高度}
    属性1: error 如果在文件上传的过程中出现问题 则标识为1 ,如果没有错误 标识为0.
    属性2: url 代表图片的虚拟访问地址. 磁盘地址
    属性3: width/height 获取图片的宽高 可以省略.

    封装文件上传的返回值VO-ImageVO

    package com.jt.vo;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Accessors(chain = true)
    public class ImageVO implements Serializable {
    
        private static final long serialVersionUID = -5302337766946721739L;
        private  Integer error;//确认图片是否有误 0 正常  1 错误
        private String url;  //图片访问的虚拟地址
        private  Integer width; //宽度
        private  Integer height; //高度
    
        //通过工具API
        public static ImageVO fail(){
            return  new ImageVO(1,null,null,null);
        }
        public static ImageVO success(String url){
            return  new ImageVO(0,url,null,null);
        }
        public static ImageVO success(String url,Integer width,Integer height){
            return  new ImageVO(0,url,width,height);
        }
    
    }
    

    文件上传的参数说明

    请求的url分析

    1596701033980

    文件上传JS属性配置:

    1596701054469

    编辑FileController

    说明: 文件上传时,需要注意富文本编辑器中传递的url参数.

    	/**
    	 * 业务分析:实现文件上传.
    	 * 1.url地址: http://localhost:8091/pic/upload
    	 * 2.参数:   uploadFile  文件上传对象
    	 * 3.返回值:  ImageVO对象
    	 */
    	@RequestMapping("/pic/upload")
    	public ImageVO uploadFile(MultipartFile uploadFile) {
    		//直接交给业务层处理	
    		return fileService.uploadFile(uploadFile);
    	}
    
    

    编辑FileService

    package com.jt.service;
    
    import javax.imageio.ImageIO;
    import java.awt.image.BufferedImage;
    
    @Service
    public class FileServiceImpl implements FileService {
        //创建根目录
        private String localDirPath ="D:/JT-SOFT/images";
        private  static Set<String> imageTypeSet = new HashSet<>();
        static {
            imageTypeSet.add(".jpg");
            imageTypeSet.add(".png");
            imageTypeSet.add(".gif");
            //.....可以动态的添加
        }
    
        /**
         *
         * 1.校验文件有效性. jpg/. png|. gif......
         * 2.校验文件是否为恶意程序 (木马. exe).jpg
         * 3.提高用户检索图片的效率  分目录存储.
         * 4.为了防止重名图片的提交自定义文件名称.
         * 5.实现图片的物理上传 本地磁盘中.
         * 6.准备一个访问图片的虚拟路径
         *  @param uploadFile
         * @return
         */
    
        @Override
        public ImageVO upload(MultipartFile uploadFile) {
            //1 校验图片类型 1) 利用正则表达式进行校验 2)指定一个集合进行校验
            //1.1获取文件名称
            String fileName= uploadFile.getOriginalFilename();
            fileName = fileName.toLowerCase();
            //1.2获取文件名称后缀,然后将获取的后缀转为小写
            String fileType = fileName.substring(fileName.lastIndexOf("."));
    
            //进行校验
            if (!imageTypeSet.contains(fileType)){
                //如果类型不匹配,应该告诉用户上传图片有误
                //
                return ImageVO.fail();
            }
            //.校验文件是否为恶意程序 (木马. exe).jpg 方法:通过图片的特有属性进行校验
            try {
               //2.1  将上传的图片利用图片API进行转化,如果不能成功转化则一定不是图片
                BufferedImage bufferedImage = ImageIO.read(uploadFile.getInputStream());
                //校验图片的特有属性 宽度和高度
                int width = bufferedImage.getWidth();
                int height = bufferedImage.getHeight();
                if (width==0 || height == 0){
                    //如果获取的宽或者高为0 则不是图片
                    return  ImageVO.fail();
                }
    
            } catch (IOException e) {
                e.printStackTrace();
                return  ImageVO.fail();
            }
            //实现分目录存储 方案1 利用hash 之后每隔2-3位进行
            //方案2 通过时间来划分目录
            //获取格式化时间 利用工具API
            String datePath = new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
            //创建文件目录 2部分 根目录+时间目录
            String localDir = localDirPath+datePath;
            File dirFile = new File(localDir);
            if (!dirFile.exists()){
                dirFile.mkdirs();
            }
            //4防止文件重名,需要自定义名称 UUID
            //4.1 生成uuid
            String uuid = UUID.randomUUID().toString().replace("-","");
            //4.2 动态生成文件名称
            String uuidName = uuid+fileType;
            //5 实现文件上传 准备文件全路径
            String realFilePath = localDir+uuidName;
            //5.1 封装文件真实对象
            File imageFile = new File(realFilePath);
            //5.2 实现文件上传
            try {
                uploadFile.transferTo(imageFile);
    
            } catch (IOException e) {
                e.printStackTrace();
                return  ImageVO.fail();
            }
            //6.暂时使用虚拟路径
            String url ="https://s1.ax1x.com/2020/08/02/atSA6U.png";
            return ImageVO.success(url);
        }
    }
    
    
    
  • 相关阅读:
    VSCode使用笔记
    python调用C++
    ubuntu下编译C++程序
    使用swig在python中调用C++
    VSCode调试data层时自身的一个bug
    MNN配置
    金融业务中的命名惯例
    Clang的线程安全分析静态工具
    gdb命名记录
    开发小结-产品类
  • 原文地址:https://www.cnblogs.com/liqbk/p/13447199.html
Copyright © 2020-2023  润新知