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")); } }