2006-京淘Day06

1 商品后台管理

1.1 动态实现商品分类展现

1.1.1 异步树加载控件说明

1).树形控件树形

每个节点都具备以下属性:

id:节点ID,对加载远程数据很重要。
text:显示节点文本。
state:节点状态,'open' 或 'closed',默认:'open'。如果为'closed'的时候,将不自动展开该节点。
checked:表示该节点是否被选中。
attributes: 被添加到节点的自定义属性。
children: 一个节点数组声明了若干节点。

2).异步树说明
树控件读取URL。子节点的加载依赖于父节点的状态。当展开一个封闭的节点,如果节点没有加载子节点,它将会把节点id的值作为http请求参数并命名为’id’,通过URL发送到服务器上面检索子节点。
如果用户点击父节点需要展开子节点时,会将父节点的id的值当做参数传递.

 

1.1.2 编辑ItemCatController(方式一)

 /**
     * 业务需求: 用户通过ajax请求,动态获取树形结构的数据.
     * url:  http://localhost:8091/item/cat/list
     * 参数: 只查询一级商品分类信息   parentId = 0
     * 返回值结果:  List<EasyUITree>
     *
     *  注意事项:
     *          1.树形结构初始化时不会传递任何信息.只有展开子节点时传递Id
     *          2.页面传递什么样的数据,后端必须接收什么样的数据
     *
     *  id: 296
     */
    @RequestMapping("/list")
    public List<EasyUITree> findItemCatList(Long id){

        Long parentId = (id==null?0L:id);
        return itemCatService.findItemCatList(parentId);
    }
 

1.1.3 编辑ItemCatController(方式二)

可以利用注解动态获取参数,并且实现转化.

//2.一般写业务需要见名知意
    @RequestMapping("/list")
    public List<EasyUITree> findItemCatList(
                @RequestParam(value = "id",defaultValue = "0") Long parentId){

        //方式1
        //Long parentId = (id==null?0L:id);
        return itemCatService.findItemCatList(parentId);
    }

1.2 关于SpringMVC参数传递说明

 

/**
     * 页面参数:  http://请求路径:/方法名称 ?id=1  name="tomcat"
     * 对象:   1.request对象 页面给服务器参数  2.response对象 服务器给页面的响应数据.
     *
     * @param id
     * @param name
     * @return
     */
    @RequestMapping("/xxxx")
    public String xxx(Long id, String name, Item item){

        /*
        1.基本类型属性赋值.
        String id = request.getParameter("id");
        Long idLong = Long.valueOf(id);
        String strArray = request.getParameter("array");
        String[]  strArrays = strArray.split(",");
        String name = request.getParameter("namexxxxx");*/
        //2.利用item对象获取属性
        /*item.getId() ~~~~去除get的前缀~~~~~~~Id~~首字母小写~~~"id"
        String id = request.getParameter("id");
        id----封装set方法----执行业务调用item.setId(id);
        Item.......*/
    }
 

总结:
1.正确编辑html标签 name属性必须书写正确 一般条件下与pojo属性相同.
2.参数接收时,校验属性的类型及属性名称是否正确. POJO属性必须写包装类型.
3.有些特定的属性可以利用SpringMVC 进行动态的转化 数组/list集合/map集合等.

1.3 商品新增

1.3.1 页面分析

1).url分析

2).参数分析

3).页面JS分析

 /*
           * $.post(url地址,参数,回调函数)
           ajax参数传递的类型有几种:
                1.json格式  {"id":"1","name":"tomcat"}
                2.字符串拼接 "id=1&name='tomcat'"
        */
        $.post("/item/save",$("#itemAddForm").serialize(), function(data){
            if(data.status == 200){
                $.messager.alert('提示','新增商品成功!');
            }else{
                $.messager.alert("提示","新增商品失败!");
            }
        });
 

1.3.2 SysResult VO对象的创建

package com.jt.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

//SysResult 主要的目的是为了与页面进行交互.  ajax/json
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class SysResult {

    private Integer status;  //200成功   201 失败
    private String  msg;     //服务器提示信息   成功  失败
    private Object  data;    //服务器返回值数据.

    //可以利用static的静态方法 将数据动态返回
    public static SysResult fail(){

        return new SysResult(201, "业务执行失败", null);
    }

    /**
     *  1.只需要返回状态码信息   200
     *  2.需要返状态及业务数据   200/data
     *  3.返回提示信息/data业务数据
     * @return
     */
    public static SysResult success(){

        return new SysResult(200, "业务执行成功!", null);
    }
    //String json = "{key:value}"
    public static SysResult success(Object data){

        return new SysResult(200, "业务执行成功!", data);
    }

    //只想返回提示信息
    public static SysResult success(String msg,Object data){

        return new SysResult(200, msg, data);
    }
}
 

1.3.3 编辑ItemController

@RequestMapping("/save")
    public SysResult saveItem(Item item){
        try {
            itemService.saveItem(item);
            return SysResult.success();
        }catch (Exception e){
            e.printStackTrace();
            return SysResult.fail();
        }
    }
 

1.3.4 编辑ItemService

@Override
    public void saveItem(Item item) {
        //思考:如果每次编辑数据库 每次都需要操作公共的属性...
        Date date = new Date();
        item.setStatus(1).setCreated(date).setUpdated(date);
        itemMapper.insert(item);
    }
 

1.4 全局异常处理机制

1.4.1 业务需求

如果再代码中频繁的添加try-cache那么导致代码的可读性差,代码的不易维护…
例如:

 

1.4.2 定义全局异常的处理机制

package com.jt.aop;

import com.jt.vo.SysResult;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.sql.SQLException;

//@ControllerAdvice  //拦截controller层
//@ResponseBody
@RestControllerAdvice   //定义全局异常的处理类   AOP=异常通知
public class SystemAOP {

    /**
     *  定义全局异常的方法  当遇到了什么异常时,程序开始执行   参数一般class类型
     *  如果一旦发生异常,则应该输出异常的信息,之后返回错误数据即可.
     */
    @ExceptionHandler({RuntimeException.class})
    public Object systemAop(Exception e){
        e.printStackTrace();
        return SysResult.fail();
    }
}

1.5 属性自动填充功能

1.5.1 MP自动填充说明

//pojo基类,完成2个任务,2个日期,实现序列化
@Data
@Accessors(chain=true)
public class BasePojo implements Serializable{
    @TableField(fill = FieldFill.INSERT) //入库时自动添加
    private Date created;
    @TableField(fill = FieldFill.INSERT_UPDATE) //入库/更新操作自动添加
    private Date updated;

}
 

1.5.2 代码自动填充功能

说明:在jt-common中添加代码自动填充的代码…

package com.jt.config;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component  //将对象交给spring容器管理
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        Date date = new Date(); //保证时间一致
        this.setInsertFieldValByName("created", date,metaObject);
        this.setInsertFieldValByName("updated", date,metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {

        this.setUpdateFieldValByName("updated", new Date(), metaObject);

    }
}

1.6 商品分类目录的回显-更新操作

1.6.1 页面js分析

 

 

1.6.2 页面效果展现

作业

完成商品 更新/删除/上架/下架 等操作…

 

 

<?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">

    <modelVersion>4.0.0</modelVersion>

    <artifactId>jt-manage</artifactId>
    <!--指定打包方式
    -->
    <packaging>war</packaging>

    <!--指定父级项目
    -->
    <parent>
        <artifactId>jt</artifactId>
        <groupId>com.jt</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <!--
        添加依赖信息
    -->

    <dependencies>
        <dependency>
            <!--依赖实质依赖的是jar包文件-->
            <groupId>com.jt</groupId>
            <artifactId>jt-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

    </dependencies>

    <!--3.添加插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

 

server:
  port: 8091
  servlet:
    context-path: /
spring:
  datasource:
    #引入druid数据源
    #type: com.alibaba.druid.pool.DruidDataSource
   #driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
    username: root
    password: root

  mvc:
    view:
      prefix: /WEB-INF/views/
      suffix: .jsp
#mybatis-plush配置
mybatis-plus:
  type-aliases-package: com.jt.pojo
  mapper-locations: classpath:/mybatis/mappers/*.xml
  configuration:
    map-underscore-to-camel-case: true

logging:
  level: 
    com.jt.mapper: debug

#关于Dubbo配置
dubbo:
  scan:
    basePackages: com.jt    #指定dubbo的包路径 扫描dubbo注解
  application:              #应用名称
    name: provider-manage     #一个接口对应一个服务名称 一个接口可以有多个实现
  registry: #注册中心 用户获取数据从从机中获取 主机只负责监控整个集群 实现数据同步
    address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183
  protocol:  #指定协议
    name: dubbo  #使用dubbo协议(tcp-ip)  web-controller直接调用sso-Service
    port: 20881  #每一个服务都有自己特定的端口 不能重复.

 

#key=value 结构 数据类型本身就是string类型
image.rootDirPath=D:/JT-SOFT/images
#image.rootDirPath=/usr/local/src/images
image.urlPath=http://image.jt.com

 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jt.mapper.ItemMapper">
   <!--留着以后用  -->
   
</mapper>

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<link rel="stylesheet" type="text/css" href="/js/jquery-easyui-1.4.1/themes/default/easyui.css" />
<link rel="stylesheet" type="text/css" href="/js/jquery-easyui-1.4.1/themes/icon.css" />
<link rel="stylesheet" type="text/css" href="/css/jt.css" />
<script type="text/javascript" src="/js/jquery-easyui-1.4.1/jquery.min.js"></script>
<script type="text/javascript" src="/js/jquery-easyui-1.4.1/jquery.easyui.min.js"></script>
<script type="text/javascript" src="/js/jquery-easyui-1.4.1/locale/easyui-lang-zh_CN.js"></script>
<!-- 自己实现业务逻辑 -->
<script type="text/javascript" src="/js/common.js"></script>

 

<%@ 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>

 

<html>
<body>
<h2>Hello World!</h2>
</body>
</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">
<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="width:700px;height:350px" id="editor"></textarea>
</body>
</html>

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>测试JSON跨域问题</title>
   <!--js引入函数类库-->
<script type="text/javascript" src="http://manage.jt.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
   <!--引入类库之后,执行js代码-->
<script type="text/javascript">
//<!--让整个页面加载完成之后执行js-->
   $(function(){
      $.get("http://manage.jt.com/test.json",function(data){
         alert(data.name);
      })
   })
</script>
</head>
<body>
   <h1>JSON跨域请求测试</h1>
</body>
</html>

 

hello({"id":"1","name":"tom"})

 

{"id":"1","name":"tom"}

 

package com.jt;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.jt.mapper")
public class SpringBootRun {
   
   public static void main(String[] args) {
      
      SpringApplication.run(SpringBootRun.class, args);
   }
}

 

package com.jt.config;

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration //标识我是一个配置类

public class MybatisPlusConfig {
//MP-Mybatis增强工具
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
        // paginationInterceptor.setOverflow(false);
        // 设置最大单页限制数量,默认 500 条,-1 不受限制
        // paginationInterceptor.setLimit(500);
        // 开启 count 的 join 优化,只针对部分 left join
        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
        return paginationInterceptor;
    }
}

 

package com.jt.vo;

import com.jt.pojo.Item;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.util.List;

@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class EasyUITable {
    private Long total;
    private List<Item> rows;
}

 

package com.jt.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.io.Serializable;

@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class EasyUITree implements Serializable {

    private Long id; //节点ID信息
    private String text;//节点的名称
    private String state;//节点的状态  open打开 close关闭
}

 

package com.jt.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class ImageVO {

    //{"error":0,"url":"图片的保存路径","width":图片的宽度,"height":图片的高度}
    private Integer error;//错误信息 0程序运行正常 1文件上传有误
    private String url;//图片访问的虚拟路径
    private Integer width;//>0
    private Integer height;//>0

    //设定上传失败方法
    public static ImageVO fail(){

        return new ImageVO(1,null,null,null);
    }

    public static ImageVO success(String url,Integer width,Integer height){

        return new ImageVO(0,url,width,height);
    }
}

 

package com.jt.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jt.pojo.ItemCat;

public interface ItemCatMapper extends BaseMapper<ItemCat> {
}

 

package com.jt.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;

import com.jt.pojo.ItemDesc;

public interface ItemDescMapper extends BaseMapper<ItemDesc> {
}

 

package com.jt.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jt.pojo.Item;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface ItemMapper extends BaseMapper<Item>{

    @Select("SELECT * FROM tb_item ORDER BY updated DESC LIMIT #{startIndex},#{rows}")
    List<Item> findItemByPage(Integer startIndex, Integer rows);
}
package com.jt.service;

import com.jt.vo.ImageVO;
import org.springframework.web.multipart.MultipartFile;

public interface FileService {
    ImageVO upload(MultipartFile uploadFile);
}
package com.jt.service;

import com.jt.pojo.ItemCat;
import com.jt.vo.EasyUITree;

import java.util.List;

public interface ItemCatService {
    ItemCat findItemCatById(Long itemCatId);

    List<EasyUITree> findItemCatList(Long parentId);

    List<EasyUITree> findItemCatListCache(Long parentId);
}
package com.jt.service;

import com.jt.pojo.Item;
import com.jt.pojo.ItemDesc;
import com.jt.vo.EasyUITable;

import java.util.List;

public interface ItemService {

    EasyUITable findItemByPage(Integer page, Integer rows);

    void saveItem(Item item, ItemDesc itemDesc);

    void updateItem(Item item, ItemDesc itemDesc);

    void deleteItems(Long[] ids);

    void updateStatus(Integer status, Long[] ids);

    ItemDesc findItemDescById(Long itemId);

    List<Item> getItems();
}
package com.jt.service;

import com.alibaba.dubbo.config.annotation.Service;
import com.jt.mapper.ItemDescMapper;
import com.jt.mapper.ItemMapper;
import com.jt.pojo.Item;
import com.jt.pojo.ItemDesc;
import org.springframework.beans.factory.annotation.Autowired;

@Service(timeout = 3000)
public class DubboItemServiceImpl implements DubboItemService{

    @Autowired
    private ItemMapper itemMapper;
    @Autowired
    private ItemDescMapper itemDescMapper;

    @Override
    public Item findItemById(Long itemId) {
        return itemMapper.selectById(itemId);
    }

    @Override
    public ItemDesc findItemDescById(Long itemId) {
        return itemDescMapper.selectById(itemId);
    }
}

 

package com.jt.service;

import com.jt.vo.ImageVO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

@Service
@PropertySource("classpath:/properties/images.properties") //容器动态加载指定的配置文件
public class FileServiceImpl implements FileService{

    //由于属性的值后期可能会发生变化,所以应该动态的获取属性数据. 利用pro配置文件
    @Value("${image.rootDirPath}")
    private String rootDirPath;             //   = "D:/JT-SOFT/images";
    @Value("${image.urlPath}")
    private String urlPath;                 // = "http://image.jt.com";

    //1.2 准备图片的集合  包含了所有的图片类型.
    private static Set<String> imageTypeSet;
    static {
        imageTypeSet = new HashSet<>();
        imageTypeSet.add(".jpg");
        imageTypeSet.add(".png");
        imageTypeSet.add(".gif");
    }


    /**
     * 完善的校验的过程
     * 1. 校验是否为图片
     * 2. 校验是否为恶意程序
     * 3. 防止文件数量太多,分目录存储.
     * 4. 防止文件重名
     * 5. 实现文件上传.
     * @param uploadFile
     * @return
     */
    @Override
    public ImageVO upload(MultipartFile uploadFile) {
        //0.防止有多余的空格 所以先做去空格的处理
        rootDirPath.trim();
        urlPath.trim();

        //1.校验图片类型  jpg|png|gif..JPG|PNG....
        //1.1 获取当前图片的名称 之后截取其中的类型.   abc.jpg
        String fileName = uploadFile.getOriginalFilename();
        int index = fileName.lastIndexOf(".");
        String fileType = fileName.substring(index);
        //将数据转化为小写
        fileType = fileType.toLowerCase();
        //1.3 判断图片类型是否正确.
        if(!imageTypeSet.contains(fileType)){
            //图片类型不匹配
            return ImageVO.fail();
        }

        //2.校验是否为恶意程序 根据宽度/高度进行判断
        try {
            //2.1 利用工具API对象 读取字节信息.获取图片对象类型
            BufferedImage bufferedImage = ImageIO.read(uploadFile.getInputStream());
            //2.2 校验是否有宽度和高度
            int width = bufferedImage.getWidth();
            int height = bufferedImage.getHeight();
            if(width==0 || height==0){
                return ImageVO.fail();
            }

            //3.分目录存储  yyyy/MM/dd 分隔
            //3.1 将时间按照指定的格式要求 转化为字符串.
            String dateDir = new SimpleDateFormat("/yyyy/MM/dd/")
                    .format(new Date());
            //3.2 拼接文件存储的目录对象
            String fileDirPath = rootDirPath + dateDir;
            File dirFile = new File(fileDirPath);
            //3.3 动态创建目录
            if(!dirFile.exists()){
                dirFile.mkdirs();
            }

            //4.防止文件重名  uuid.jpg 动态拼接
            //4.1 动态生成uuid  实现文件名称拼接  名.后缀
            String uuid =
                    UUID.randomUUID().toString().replace("-", "");
            String realFileName = uuid + fileType;

            //5 实现文件上传
            //5.1 拼接文件真实路径 dir/文件名称.
            String realFilePath = fileDirPath + realFileName;
            //5.2 封装对象  实现上传
            File realFile = new File(realFilePath);
            uploadFile.transferTo(realFile);

            //实现文件上传成功!!! http://image.jt.com\2020\09\30\a.jpg
            String url = urlPath + dateDir + realFileName;
            return ImageVO.success(url,width,height);
        } catch (IOException e) {
            e.printStackTrace();
            return ImageVO.fail();
        }
    }
}

 

package com.jt.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jt.anno.CacheFind;
import com.jt.mapper.ItemCatMapper;
import com.jt.pojo.ItemCat;
import com.jt.util.ObjectMapperUtil;
import com.jt.vo.EasyUITree;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;

import java.util.ArrayList;
import java.util.List;

@Service
public class ItemCatServiceImpl implements ItemCatService{

    @Autowired
    private ItemCatMapper itemCatMapper;

    @Autowired(required = false)//保证后续操作正常执行 可以懒加载
    private Jedis jedis;

    @Override
    public ItemCat findItemCatById(Long itemCatId) {

        return itemCatMapper.selectById(itemCatId);
    }

    /**
     * 返回值:List<EasyUITree>集合信息
     * 数据库查询返回值:List<ItemCat>
     *     数据类型必须手动的转化
     *
     * @param parentId
     * @return
     */
    @Override
    @CacheFind(preKey = "ITEM_CAT_PARENTID")
    public List<EasyUITree> findItemCatList(Long parentId) {
        //1.查询数据库记录
        QueryWrapper<ItemCat> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("parent_id", parentId);
        List<ItemCat> catList=itemCatMapper.selectList(queryWrapper);

        //2.需要catList集合转化为voList 一个一个转化
        List<EasyUITree> treeList=new ArrayList<>();
        for (ItemCat itemCat:catList){
            Long id=itemCat.getId();
            String name=itemCat.getName();
            //如果是父级 应该closed 如果不是父级 应该是open
            String state=itemCat.getIsParent()?"closed":"open";
            EasyUITree tree=new EasyUITree(id,name,state);
            treeList.add(tree);
        }
        return treeList;
    }

    @Override
    public List<EasyUITree> findItemCatListCache(Long parentId) {
        //0.定义公共的返回值对象
        List<EasyUITree> treeList=new ArrayList<>();
        //1.定义key
        String key="ITEM_CAT_PARENTID::"+parentId;
        //2.检索redis服务器,是否含有该key

        //记录时间
        Long startTime=System.currentTimeMillis();
        if (jedis.exists(key)){
            //数据存在
            String json=jedis.get(key);

            Long endTime=System.currentTimeMillis();
            //需要将json串转化为对象
            treeList=ObjectMapperUtil.toObj(json, treeList.getClass());
            System.out.println("从redis中获取数据 耗时:"+(endTime-startTime)+"毫秒");
        }else {
            //3.数据不存在 查询数据库
            treeList=findItemCatList(parentId);
            Long endTime=System.currentTimeMillis();

            //3.将数据保存到缓存中
            String json=ObjectMapperUtil.toJSON(treeList);
            jedis.set(key,json);
            System.out.println("查询数据库 耗时:"+(endTime-startTime)+"毫秒");
        }
        return treeList;
    }
}

 

package com.jt.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jt.mapper.ItemDescMapper;
import com.jt.pojo.Item;
import com.jt.pojo.ItemDesc;
import com.jt.vo.EasyUITable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.jt.mapper.ItemMapper;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;

@Service
@Transactional//控制事务
public class ItemServiceImpl implements ItemService {
   
   @Autowired
   private ItemMapper itemMapper;

   @Autowired
   private ItemDescMapper itemDescMapper;

   /**
    * 尝试使用MP的方式进行分页操作
    * @param page
    * @param rows
    * @return
    */
   @Override
   public EasyUITable findItemByPage(Integer page, Integer rows) {

      QueryWrapper<Item> queryWrapper=new QueryWrapper<>();
      queryWrapper.orderByDesc("updated");
      //暂时只封装了2个数据,页数/条数
      IPage<Item> iPage=new Page<>(page,rows);
      //MP传递了对应的参数,则分页就会在内部完成,返回分页对象
      iPage=itemMapper.selectPage(iPage,queryWrapper);

      //1.获取分页的总记录数
      Long total=iPage.getTotal();
      //2.获取分页的结果
      List<Item> list=iPage.getRecords();
      return new EasyUITable(total,list);
   }

   @Override
   public void saveItem(Item item, ItemDesc itemDesc) {
      //思考:如果每次编辑数据库,每次都需要操作公共的属性....
      //Date date=new Date();
      //完成自动填充功能
      //item.setStatus(1).setCreated(date).setUpdated(date);
      item.setStatus(1);
      //如果完成入库操作时,应该动态回显主键信息
      //MP的方式实现数据库入库操作,MP会自动的实现主键信息的回显....
      itemMapper.insert(item);

      //itemDesc属性有值
      itemDesc.setItemId(item.getId());
      itemDescMapper.insert(itemDesc);
   }



   @Transactional
   @Override
   public void updateItem(Item item,ItemDesc itemDesc) {
      //更新的时间由程序自动填充....
      itemMapper.updateById(item);

      itemDesc.setItemId(item.getId());
      itemDescMapper.updateById(itemDesc);
   }

   @Transactional
   @Override
   public void deleteItems(Long[] ids) {

      //1.将数组转化为集合
      List<Long> longList= Arrays.asList(ids);
      itemMapper.deleteBatchIds(longList);

      //2.删除商品详情信息
      itemDescMapper.deleteBatchIds(longList);
   }

   /**
    * sql:update tb_item set status =#{status},updated={date}
    * where id in (id1,id2,id3)
    * MP机制实现
    * @param status
    * @param ids
    */
   @Override
   public void updateStatus(Integer status, Long[] ids) {

      Item item=new Item();//封装修改的值
      item.setStatus(status);
      UpdateWrapper<Item>  updateWrapper=new UpdateWrapper<>();
      updateWrapper.in("id", Arrays.asList(ids));
      itemMapper.update(item,updateWrapper);
   }

   @Override
   public ItemDesc findItemDescById(Long itemId) {
      return itemDescMapper.selectById(itemId);
   }

   @Override
   public List<Item> getItems() {
      return itemMapper.selectList(null);
   }


   /**
    * 分页查询商品的信息
    * sql语句:每页20行
    * select * from tb_item limit 起始位置,查询的行数
    * 查询第一页
    *     select * from tb_item limit 0,20; [0-19]
    *     查询第二页
    *     select * from tb_item limit 20,20;[20-39]
    *
    * 查询第三页
    * select * from tb_item limit 40,20;[40-59]
    *
    *     第n页
    *        select * from tb_item limit (n-1)*rows,rows;[40-59]
    *
    * @param rows
    * @return
    */
// @Override
// public EasyUITable findItemByPage(Integer page, Integer rows) {
//    //1.手动完成分页操作
//    int startIndex=(page-1)*rows;
//    //2.数据库记录
//    List<Item> itemList = itemMapper.findItemByPage(startIndex,rows);
//
//    //3.查询数据库总记录数
//    Long total = Long.valueOf(itemMapper.selectCount(null));
//    //4.将数据库记录封装为vo对象
//    return new EasyUITable(total,itemList);
// }


}

 

package com.jt.controller;

import com.jt.service.FileService;
import com.jt.vo.ImageVO;
import org.springframework.beans.factory.annotation.Autowired;
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.InputStream;

@RestController
public class FileController {

    @Autowired
    private FileService fileService;

    /**文件上传的入门案例
     * url:http://localhost:8091/file
     * 参数:fileImage 名称
     * 返回值: 文件上传成功
     *
     * 文件上传的具体步骤:
     * 1.准备文件目录
     * 2.准备文件的全名  xxx.jpg
     * 3.准备文件上传路径  D:/JT-SOFT/images/xxx.jpg
     * 4.将字节的信息输出即可
     *大小不要超过1M
     */

    @RequestMapping("/file")
    public String file(MultipartFile FileImage) throws Exception{

        String dirPath="D:/JT-SOFT/images";
        File dirFile=new File(dirPath);
        if (!dirFile.exists()){
            dirFile.mkdirs();//一劳永逸的写法
        }

        //获取文件的名称
        String fileName=FileImage.getOriginalFilename();
        //获取文件全路径
        String filePath=dirPath+"/"+fileName;
        File file=new File(filePath);
        FileImage.transferTo(file);//将字节信息输出到指定的位置中
        return "文件上传成功!!!";
    }

    /**
     * 实现文件上传
     * url地址:http://localhost:8091/pic/upload?dir=image
     * 参数:uploadFile:文件字节信息
     * 返回值:{"error":0,"url":"图片的保存路径","width":图片的宽度,"height":图片的高度}
     *          ImageVO对象....
     */

    @RequestMapping("/pic/upload")
    public ImageVO upload(MultipartFile uploadFile){

        return fileService.upload(uploadFile);
    }



}

 

package com.jt.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller
public class IndexController {

   /**
    * 业务需求:
    *     实现用户页面的跳转
    * url:http://localhost:8091/page/item-add  页面:item-add
    * url:http://localhost:8091/page/item-list  页面:item-list
    *
    *
    * 能否利用一个方法实现通用页面的跳转功能
    * 实现思路:如果能够动态的获取url中的参数就可以实现页面的跳转 restful风格
    * restFul语法:
    * 1.参数必须使用"/"分隔
    * 2.参数必须使用{}形式包裹
    * 3.参数接收时需要使用@PathVariable获取
    *
    * restFul风格用法2:
    *     利用不同的请求的类型,定义不同的业务功能!!!
    *     type="GET",   查询业务
    *     type="POST",   参数提交新增操作
    *     type="PUT",       更新操作
    *     type="DELETE", 删除操作
    * @return
    */



   //@RequestMapping(value = "/page/{moduleName}",method = RequestMethod.GET)
   @GetMapping("/page/{moduleName}")
// @PutMapping
// @PostMapping
// @DeleteMapping
   public String module(@PathVariable String moduleName) {
      
      return moduleName;
   }
}
package com.jt.controller;

import com.jt.pojo.ItemCat;
import com.jt.service.ItemCatService;
import com.jt.vo.EasyUITree;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/item/cat")
public class ItemCatController {

    @Autowired
    private ItemCatService itemCatService;


    /**
     *url: /item/cat/queryItemName
     * 用户参数:{itemCatId:val}
     * 返回值:商品分类的名称
     */
    @RequestMapping("/queryItemName")
    public String findItemCatNameById(Long itemCatId){

        //根据商品分类id查询商品分类对象
        ItemCat itemCat=itemCatService.findItemCatById(itemCatId);
        return itemCat.getName();//返回商品分类的名称
    }

    /**
     * 业务需求:用户通过ajax请求,动态获取树形结构的数据
     * url: http://localhost:8091/item/cat/list
     * 参数:只查询一级商品分类信息 parentId=0
     * 返回结果:List<EasyUITree>
     *
     *     注意事项:
     *     1.树形结构初始化时,不会传递任何信息,只有展开子节点时传递id
     *     页面传递什么样的数据,后端必须接收什么样的数据
     *     id: 296
     *
     * springmvc参数获取的过程....
     * 页面参数:id:296  name=xxxx;
     * mvc参数: xxx(Long id,String name);
     *
     *
     *     2.一般写业务需要见名知意
     */
    @RequestMapping("/list")
    public List<EasyUITree> findItemCatList(
            @RequestParam(value = "id",defaultValue = "0") Long parentId){

        //方式1:
        //Long parentId=(id==null?0L:id);
        return itemCatService.findItemCatList(parentId);
       // return itemCatService.findItemCatListCache(parentId);
    }


}

 

package com.jt.controller;

import com.jt.pojo.Item;
import com.jt.pojo.ItemDesc;
import com.jt.vo.EasyUITable;
import com.jt.vo.SysResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import com.jt.service.ItemService;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/item")
@RestController  //由于ajax调用 采用json串返回
public class ItemController {
   
   @Autowired
   private ItemService itemService;

   /**
    * url:http://localhost:8091/item/query?page=1&rows=20
    * 请求参数:page=1&rows=20
    * 返回值结果:EasyUITable
    */
   @RequestMapping("/query")
   public EasyUITable findItemByPage(Integer page,Integer rows){

      return itemService.findItemByPage(page,rows);
   }

   /**
    * 业务需求:
    *     完成商品入库操作,如果成功应该返回vo对象
    *     url:/item/save
    *     参数:整个表单数据
    *     返回值:SysResult Vo对象
    */
   @RequestMapping("/save")
   public SysResult saveItem(Item item, ItemDesc itemDesc){

      itemService.saveItem(item,itemDesc);
      return SysResult.success();

//    try {
//       itemService.saveItem(item);
//       return SysResult.success();
//    }catch (Exception e){
//       e.printStackTrace();
//       return SysResult.fail();
//    }
   }

   /**
    * 商品修改操作
    * 1.url地址:http://localhost:8091/item/update
    * 2.参数:form表单提交
    * 3.返回值 SysResult对象
    */

   @RequestMapping("/update")
   public SysResult updateItem(Item item,ItemDesc itemDesc){

      itemService.updateItem(item,itemDesc);
      return SysResult.success();
   }

   /**
    *业务:商品删除
    * url地址:http://localhost:8091/item/delete
    * 参数:ids: 1474391967
    * 返回值:系统返回值VO
    *
    * List 可以赋值 name="list[0]" value=100
    *              name="list[1]" value=200
    */

   @RequestMapping("/delete")
   public SysResult deleteItems(Long... ids){

      itemService.deleteItems(ids);
      return SysResult.success();
   }


   /**
    * 实现商品的下架
    * url地址:http://localhost:8091/item/updateStatus/2  status=2
    *           http://localhost:8091/item/updateStatus/1  status=1
    *     利用RestFul风格实现通用的操作
    * 参数:ids: 1474391967
    * 返回值:vo对象
    */

   @RequestMapping("/updateStatus/{status}")
   public SysResult updateStatus(@PathVariable Integer status,Long[] ids){

      itemService.updateStatus(status,ids);
      return SysResult.success();
   }

   /**
    * 业务:动态获取商品详情信息
    * url地址:http://localhost:8091/item/query/item/desc/1474391966
    * 参数:itemId restFul方式获取
    * 返回值:系统vo的对象
    */

   @RequestMapping("/query/item/desc/{itemId}")
   public SysResult findItemDescById(@PathVariable Long itemId){

      ItemDesc itemDesc=itemService.findItemDescById(itemId);
      return SysResult.success(itemDesc);
   }





}

 

package com.jt.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.sound.sampled.Port;

@RestController
public class PortController {

    //从spring服务器中动态的获取端口号
    @Value("${server.port}")
    private Integer port;

    @RequestMapping("/getPort")
    public String getPort(){

        return "当前服务器访问的端口号:"+port;
    }
}

 

package com.jt.web.controller;

import com.jt.pojo.Item;
import com.jt.service.ItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class HttpClientController {

    @Autowired
    private ItemService itemService;

    /**
     * url请求地址:http://manage.jt.com/getItems
     */
    @RequestMapping("/getItems")
    public List<Item> getItems(){

        return itemService.getItems();
    }
}

 

package com.jt.web.controller;

import com.fasterxml.jackson.databind.util.JSONPObject;
import com.jt.pojo.ItemDesc;
import com.jt.util.ObjectMapperUtil;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class JSONPController {

    /**
     * 实现jsonp跨域请求
     * url地址:http://manage.jt.com/web/testJSONP?callback=xxxxx
     * 参数:暂时没有可以不接
     * 返回值:callback(JSON)
     */

//    @RequestMapping("/web/testJSONP")
//    public String testJSONP(String callback){
//
//        ItemDesc itemDesc=new ItemDesc();
//        itemDesc.setItemId(1000L).setItemDesc("JSONP测试!!!!!");
//
//        String json= ObjectMapperUtil.toJSON(itemDesc);
//        return callback+"("+json+")";
//    }

    @RequestMapping("/web/testJSONP")
  public JSONPObject testJSONP(String callback) {

        ItemDesc itemDesc=new ItemDesc();
        itemDesc.setItemId(1000L).setItemDesc("JSONP测试!!!!!");
        return new JSONPObject(callback, itemDesc);
    }




}

 

package com.jt.test;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jt.pojo.ItemDesc;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class TestObjectMapper {

    /**
     * 测试简单对象的转化
     */
    @Test
    public void test01() throws JsonProcessingException {

        ObjectMapper objectMapper=new ObjectMapper();
        ItemDesc itemDesc=new ItemDesc();
        itemDesc.setItemId(100L).setItemDesc("商品详情信息")
                .setCreated(new Date()).setUpdated(new Date());
        //对象转换为json
        String json=objectMapper.writeValueAsString(itemDesc);
        System.out.println(json);

        //json转化为对象
        ItemDesc itemDesc2=objectMapper.readValue(json, ItemDesc.class);
        System.out.println(itemDesc2.getItemDesc());
    }


    /**
     * 测试集合对象的转化
     */
    @Test
    public void test02() throws JsonProcessingException {

        ObjectMapper objectMapper=new ObjectMapper();
        ItemDesc itemDesc=new ItemDesc();
        itemDesc.setItemId(100L).setItemDesc("商品详情信息1")
                .setCreated(new Date()).setUpdated(new Date());

        ItemDesc itemDesc2=new ItemDesc();
        itemDesc2.setItemId(100L).setItemDesc("商品详情信息2")
                .setCreated(new Date()).setUpdated(new Date());
        List<ItemDesc> lists=new ArrayList<>();
        lists.add(itemDesc);
        lists.add(itemDesc2);

        //[{key:value},{}]
        String json=objectMapper.writeValueAsString(lists);
        System.out.println(json);

        //将json串转化为对象
        List<ItemDesc> list2=objectMapper.readValue(json, lists.getClass());
        System.out.println(list2);
    }
}
package com.jt.test;

import lombok.SneakyThrows;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.*;
import redis.clients.jedis.params.SetParams;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class testRedis {

    /**
     * 1.1测试redis程序链接是否正常
     * 步骤:
     * 1.实例化jedis工具API对象(host:port)
     * 2.根据实例 操作redis 方法就是命令
     *
     *
     * 关于启动不通的说明:
     * 1.检查Linux防火墙
     * 2.检查Redis配置文件修改项
     *  2.1IP绑定
     *  2.2保护模式
     *  2.3后台启动
     *
     * 3.检查redis启动方式 redis-server redis.conf
     * 4.检查IP 端口 及redis是否启动....
     */

    @Test
    public void test01(){

        String host="192.168.126.129";
        int port=6379;
        Jedis jedis=new Jedis(host,port);
        jedis.set("cgb2006", "好好学习 天天向上");
        System.out.println(jedis.get("cgb2006"));
    }

    /**
     * 2.需求:
     * 1.向redis中插入数据 k-v
     * 2.为key设定超时时间 60秒后失效
     * 3.线程sleep 3秒
     * 4.获取key的剩余的存活时间
     *
     * 问题描述:数据一定会被删除吗?
     * 问题说明:如果使用redis 并且需要添加超时时间时,一般需要满足原子性
     * 要求
     * 原子性:操作时,要么成功,要么失败,但是必须同时完成
     *
     */

@Test
    public void test02() throws Exception{

    Jedis jedis=new Jedis("192.168.126.129",6379);
    jedis.setex("宝可梦", 60,"小火龙 妙蛙种子" );
    System.out.println(jedis.get("宝可梦"));

//        Jedis jedis=new Jedis("192.168.126.129",6379);
//        jedis.set("宝可梦", "小火龙 妙蛙种子");
//        int a=1/0;//可能会出异常
//        jedis.expire("宝可梦", 60);
//        Thread.sleep(3000);
//        System.out.println(jedis.ttl("宝可梦"));
    }

    /**
     * 3.需求:如果发现key已经存在时,不修改数据,如果key不存在时才会修改数据
     *
     */

    @Test
    public void test03() throws Exception {

        Jedis jedis = new Jedis("192.168.126.129", 6379);
        jedis.setnx("aaaa", "测试nx的方法");
//        if(jedis.exists("aaa")){
//            System.out.println("key已经存在 不做修改");
//        }else{
//            jedis.set("aaa", "测试数据");
//        }
        System.out.println(jedis.get("aaaa"));
    }

/**
 * 需求:
 * 1.要求用户赋值时,如果数据存在则不赋值,setnx
 * 2.要求在赋值操作时,必须设定超时的时间,并且要求满足原子性 setex
 */

@Test
public void test04() throws Exception {

    Jedis jedis = new Jedis("192.168.126.129", 6379);
    SetParams setParams=new SetParams();
    setParams.nx().ex(20);//加锁操作
    String result=jedis.set("bbbb", "实现业务操作",setParams);
    System.out.println(result);
    System.out.println(jedis.get("bbbb"));
    //jedis.del("bbbb");//解锁操作
}

/**
 * 测试Redis分片机制
 * 思考:shards如何确定应该存储到哪台redis中呢?
 */

    @Test
    public void testShards(){
        List<JedisShardInfo> shards=new ArrayList<>();
        shards.add(new JedisShardInfo("192.168.126.129",6379));
        shards.add(new JedisShardInfo("192.168.126.129",6380));
        shards.add(new JedisShardInfo("192.168.126.129",6381));
        //准备分片的对象
        ShardedJedis shardedJedis=new ShardedJedis(shards);
        shardedJedis.set("shards", "redis分片测试");
        System.out.println(shardedJedis.get("shards"));
    }

    /**
     * 测试redis哨兵
     */

    @Test
    public void testSentinel(){
        Set<String> set =new HashSet<>();
        //1.传递哨兵的配置信息
        set.add("192.168.126.129:26379");
        JedisSentinelPool sentinelPool = new JedisSentinelPool("mymaster", set);
        Jedis jedis=sentinelPool.getResource();
        jedis.set("aa", "哨兵测试");
        System.out.println(jedis.get("aa"));
        jedis.close();
    }

    /**
     * key如何保存到redis中的??  3台主机
     * redis分区算法
     */

    @Test
    public void testCluster(){
        Set<HostAndPort> nodes=new HashSet<>();
        nodes.add(new HostAndPort("192.168.126.129", 7000));
        nodes.add(new HostAndPort("192.168.126.129", 7001));
        nodes.add(new HostAndPort("192.168.126.129", 7002));
        nodes.add(new HostAndPort("192.168.126.129", 7003));
        nodes.add(new HostAndPort("192.168.126.129", 7004));
        nodes.add(new HostAndPort("192.168.126.129", 7005));

        JedisCluster jedisCluster=new JedisCluster(nodes);
        jedisCluster.set("cluster", "集群的测试");
        System.out.println(jedisCluster.get("cluster"));

    }

}

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值