/*业务需求:商品列表的展现 请求路径: /item/getItemList?query=&pageNum=1&pageSize=10 请求类型: get 请求参数: 使用pageResult对象接收 返回值:SysResult(pageResult) * */ //@PathVariable restful动态获取参数 @GetMapping("/getItemList") public SysResult getItemList(PageResult pageResult){//3个参数 pageResult=itemService.getItemList(pageResult);//3+2 return SysResult.success(pageResult); }
/* * sql:select * from item limit 起始位置,显示条数 * * */ @Override public PageResult getItemList(PageResult pageResult) { //1.构建模糊查询 boolean flag= StringUtils.hasLength(pageResult.getQuery());//动态sql,为true才拼接条件 QueryWrapper<Item> queryWrapper = new QueryWrapper<>(); queryWrapper.like(flag,"title", pageResult.getQuery()); //2.定义分页对象 //页数 条数 IPage page=new Page(pageResult.getPageNum(), pageResult.getPageSize()); //page的参数由原来的页数/条数 ,经过业务调用添加了 总记录数和分页的结果 page=itemMapper.selectPage(page,queryWrapper); long total=page.getTotal();//获取总数 List<Item> rows=page.getRecords();//获取分页的结果 return pageResult.setTotal(total).setRows(rows); }
@Configuration //标识配置类 public class MybatisPlusConfig { //将自定义对象交给容器管理 告诉MP 当前使用的数据库是mysql/maridb @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }
说明: item的基本信息与ItemDesc的详情信息 可以采用对象的方式进行包裹.
例如: {item: item的数据信息, itemDesc: itemDesc的数据信息}
请求路径: http://localhost:8091/item/saveItem 请求类型: post 前端传递参数分析
{ item: { images: "/2021/05/20/da0c1d4781c1499399f090da8b60f359.jpg,/2021/05/20/2ac1c34776a7465887eb019655354c3c.jpg" itemCatId: 560 num: "100" price: 718800 sellPoint: "【华为官方直供,至高12期免息0首付,原装正品】送华为原装无线充+运动蓝牙耳机+蓝牙音箱+三合一多功能数据线+钢化膜等!" title: "华为P40 Pro 5G手机【12期免息可选送豪礼】全网通智能手机" }, itemDesc: { itemDesc: "<ul><li>品牌: <a href=https://list.jd.com/list.html"....... " }, itemParam: { dynamicArray: [ {paramId: 1, paramVals: "亮黑色,釉白色"}, {paramId: 2, paramVals: "8GB+128GB,8GB+256GB"} ], staticArray: [ {"paramId": 3,"paramVals": "华为Mate 40 Pro"}, {"paramId": 4,"paramVals": "0.575kg"}..... ] } }
请求参数: 使用ItemVO对象接收
参数名称 | 参数类型 | 参数说明 | 备注 |
---|---|---|---|
item | Item | 商品基本信息对象封装 | 不能为null |
itemDesc | ItemDesc | 商品详情信息 | 不能为null |
把Item和ItemDesc封装到一个ItemVO对象中
@Data @Accessors(chain = true) public class ItemVO implements Serializable { private Item item; private ItemDesc itemDesc; }
/*商品新增 请求路径: /item/saveItem 请求类型: post 参数信息: itemVO对象 * */ @PostMapping("/saveItem") public SysResult saveItem(@RequestBody ItemVO itemVO){//Item+ItemDesc itemService.saveItem(itemVO); return SysResult.success(); }
/** * 需求: 完成2部分入库操作 * 步骤1: 完成Item入库操作 * 步骤2: 完成ItemDesc入库操作 item.id=itemDesc.id * mybatis 知识讲解 * <insert id="xxxx" useGeneratedKeys="true" * keyColumn="id" * keyProperty="id"> * 新增sql * </insert> * MP知识讲解: * MP基于对象的方式操作数据,如果实现数据的入库操作, * 则数据都会与对象绑定,动态回显. * 难点知识: 如何实现数据回显!!!!!! * @param itemVO */ @Override @Transactional public void saveItem(ItemVO itemVO) { //1.步骤1 实现Item对象入库 Item item = itemVO.getItem().setStatus(true); //刚开始id为null,入库操作时候,id在数据库中会自动赋值 //赋值之后,对象中的ID依然为null itemMapper.insert(item); //2.步骤2 实现ItemDesc对象入库 ItemDesc itemDesc = itemVO.getItemDesc(); itemDesc.setId(item.getId()); itemDescMapper.insert(itemDesc); }
/* 请求路径: /item/deleteItemById 请求类型: delete 请求参数: id */ @DeleteMapping("/deleteItemById") public SysResult deleteItemById(Integer id){ itemService.deleteItemById(id); return SysResult.success(); }
item和item_desc都要一起删除
@Override @Transactional public void deleteItemById(Integer id) { itemMapper.deleteById(id); itemDescMapper.deleteById(id); }
/* /item/updateItemStatus */ @PutMapping("/updateItemStatus") public SysResult updateItemStatus(@RequestBody Item item){ itemService.updateItemStatus(item); return SysResult.success(); }
@Override @Transactional public void updateItemStatus(Item item) { itemMapper.updateById(item); }
说明:当用户选择多张图片时,则是一张一张的传输.
请求路径: http://localhost:8091/file/upload
请求类型: post
请求参数:
参数名称 | 参数说明 | 备注 |
---|---|---|
file | 文件上传的参数名称 | file中携带的是二进制信息 |
ImageVO对象说明
参数名称 | 参数类型 | 参数说明 | 备注 |
---|---|---|---|
virtualPath | String | virtualPath | 例如: 2021/11/11/a.jpg 不需要写磁盘地址 |
urlPath | String | urlPath | http://image.jt.com/2021/11/11/a.jpg 需要指定域名地址 |
fileName | String | 文件上传后的文件名称 | UUID.type |
@Data @Accessors(chain = true) @NoArgsConstructor @AllArgsConstructor public class ImageVO implements Serializable { private String virtualPath; //虚拟路径 动态变化的路径 private String urlPath; //图片网络地址 private String fileName; //图片名称 }
@RestController @CrossOrigin @RequestMapping("/file") public class FileController { /** * URL: /file/upload * 类型: post * 参数: file=字节信息 * 返回值: SysResult(ImageVO) * 知识点: * SpringMVC针对与IO操作开发了MultipartFile * 底层实现就是常规IO流,简化了用户的操作过程.无需手动关流 * SpringMVC中默认支持最大1M * 步骤: * 1.获取文件名称 * 2.准备文件路径 * 3.准备文件上传的全路径 * 4.实现文件上传操作 */ @PostMapping("/upload") public SysResult upload(MultipartFile file) throws IOException { //1.获取文件名称 a.jpg String fileName = file.getOriginalFilename(); //2.准备文件目录 String dir = "D:/project3/images"; File dirFile = new File(dir); if(!dirFile.exists()){//判断目录是否存在 dirFile.mkdirs(); //创建多级目录 } String path = dir + "/" + fileName; //实现文件上传 file.transferTo(new File(path)); return SysResult.success(); } }
@PostMapping("/upload") public SysResult fileUpload(MultipartFile file){ ImageVO imageVO=fileService.upload(file); if (imageVO==null){ return SysResult.fail(); } return SysResult.success(imageVO); }
@Override public ImageVO upload(MultipartFile file) { //1. //获取图片名称全部转小写 String filename = file.getOriginalFilename().toLowerCase(); if (!filename.matches("^.+\\.(jpg|png|gif)$")) {//java中 \\ 代表 \ ;不识别单个\ return null; } //2.通过校验宽度和高度判断是否为图片 try { BufferedImage bufferedImage = ImageIO.read(file.getInputStream()); int width = bufferedImage.getWidth(); int height = bufferedImage.getHeight(); if (width == 0 || height == 0) { return null; } } catch (IOException e) { //一般条件下,为了不影响代码结构,将检查异常,转化为运行时异常 e.printStackTrace(); throw new RuntimeException(e);// } return null; }
@Override public ImageVO upload(MultipartFile file) { //1. //获取图片名称全部转小写 String fileName = file.getOriginalFilename().toLowerCase(); if (!fileName.matches("^.+\\.(jpg|png|gif)$")) {//java中 \\ 代表 \ ;不识别单个\ return null; } //2.通过校验宽度和高度判断是否为图片 try { BufferedImage bufferedImage = ImageIO.read(file.getInputStream()); int width = bufferedImage.getWidth(); int height = bufferedImage.getHeight(); if (width == 0 || height == 0) { return null; } //3 分目录存储 String datePath = new SimpleDateFormat("/yyyy/MM/dd/").format(new Date()); String fileDir = rootDir + datePath; File dirFile = new File(fileDir);// if (!dirFile.exists()) { dirFile.mkdirs(); } //4.动态生成UUID String UUID = java.util.UUID.randomUUID().toString(); int index = fileName.lastIndexOf("."); String fileType = fileName.substring(index); fileName = UUID + fileType; //5.实现文件上传 String path = fileDir + "/" + fileName; file.transferTo(new File(path)); //6.准备imageVO的数据返回 String virtualPath = datePath + fileName; //String urlPath="https://img14.360buyimg.com/n0/jfs/t1/162878/20/21270/387542/61b8da25Ed63246d6/baffb7e01f3edefb.jpg"; String urlPath = rootURL + virtualPath; //String urlPath = rootDir + virtualPath; System.out.println(urlPath); ImageVO imageVO = new ImageVO(virtualPath, urlPath, fileName); return imageVO; } catch (IOException e) { //一般条件下,为了不影响代码结构,将检查异常,转化为运行时异常 e.printStackTrace(); throw new RuntimeException(e);// } }
/* 请求路径: /file/deleteFile 请求类型: delete 请求参数: virtualPath 返回值: SysResult */ @DeleteMapping("/deleteFile") public SysResult deleteFile(String virtualPath){ fileService.deleteFile(virtualPath); return SysResult.success(); }
/* 删除文件 需要文件全路径 */ @Override public void deleteFile(String virtualPath) { String localPath=rootDir+virtualPath; File file = new File(localPath); if (file.exists()) {//如果文件存在则删除 file.delete(); } }
需求说明: 当用户完成图片上传之后 会根据网络地址访问图片,但是查找的图片一定存在于磁盘中.
URL地址: http://image.jt.com/2021/12/16/f9981c76-e6a7-49fa-88d9-3be0851dbf50.jpg
磁盘地址: D:/project3/images/2021/12/16/f9981c76-e6a7-49fa-88d9-3be0851dbf50.jpg
技术难点:
1.当用户访问URL网络地址时,应该按照磁盘地址进行查找!
如何将网络地址转化为磁盘地址?
反向代理服务器位于用户与目标服务器之间,但是对于用户而言,反向代理服务器就相当于目标服务器,即用户直接访问反向代理服务器就可以获得目标服务器的资源。同时,用户不需要知道目标服务器的地址,也无须在用户端作任何设定。反向代理服务器通常可用来作为Web加速,即使用反向代理作为Web服务器的前置机来降低网络和服务器的负载,提高访问效率。
如果网站将真实地址直接告知用户.导致整个服务器不安全. 所以需要采用代理的技术规避该问题.
反向代理服务器介于用户和目标服务器之间 用户从反向代理服务器获取资源, 用户以为反向代理服务器就是目标服务器. 用户不清楚真实的服务器到底是谁, 保护了真实服务器的信息. 也称之为 "服务器端代理"
正向代理,意思是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端才能使用正向代理。
正向代理服务器介于客户端和原始服务器之间.
用户访问正向代理服务器,并且指定目标服务器地址.
服务器端不清楚到底是谁访问的,以为是正向代理服务器访问的. 保护了用户信息. 也称之为客户端代理
.
Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的,第一个公开版本0.1.0发布于2004年10月4日。
其将源代码以类BSD许可证的形式发布,因它的稳定性、丰富的功能集、简单的配置文件和低系统资源的消耗而闻名。2011年6月1日,nginx 1.0.4发布。
Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
nginx是一块开源免费的 轻量级的反向代理服务器/web服务器. nginx并发能力强 理论值: 5万次/秒 实际值: 3万次/秒 tomcat: 150-220 —>1000个/秒 内存占用200M nginx占用内存少 不超过2M
URL地址: http://nginx.org/en/download.html
说明:
1.nginx启动会占用80端口!!
2.nginx启动路径不要有中文/空格/特殊字符 底层开发语言:C语言
访问测试:
检查端口号占用
说明: nginx的启动每次都会启动2个进程项.
主进程: 主要提供反向代理服务. 占用内存大的
守护进程: 防止主进程意外关闭. 占用内存小的
任务管理器 进程
说明: nginx的命令需要在根目录中运行 nginx.exe 所在的路径就是根目录
命令:
http { #每个反向代理服务,就是一个server server { #nginx默认监听端口号 默认都是80 listen 80; #nginx要拦截的域名 server_name localhost; #拦截所有的请求 location / { # root 代表代理的是一个目录 root html; # 配置默认访问的首页 index index.html index.htm; } } }
URL地址: http://image.jt.com/2021/12/16/f9981c76-e6a7-49fa-88d9-3be0851dbf50.jpg
磁盘地址: D:/project3/images/2021/12/16/f9981c76-e6a7-49fa-88d9-3be0851dbf50.jpg
代理机制:
域名: http://image.jt.com:80
代理为:
D:/project3/images
配置图片代理:
#配置图片代理 server { listen 80; server_name image.jt.com; location / { root D:/project3/images; } }
编辑完成之后,重启nginx
文件位置: C:\Windows\System32\drivers\etc
如果该文件为只读 应该去除只读选项
127.0.0.1 localhost 127.0.0.1 image.jt.com #图片 127.0.0.1 manage.jt.com #后端 127.0.0.1 web.jt.com #前端
1.检查所有的sql中的表名是否存在大小写问题. 检查注解 检查Sql
2.根据码云 检查POM.xml文件内容
3.将项目打包 install 命令
4.前端项目打包
检查是否生成dist目录
1.修改main.js的路径
2.编辑AddItem.vue文件
3.将前端项目进行编译
如果将上述的操作修改完成,之后需要将程序编译。如图所示
将编译之后的dist目录 复制到nginx的根目录中。
需求: 用户通过http://web.jt.com 访问 dist/index.html
#配置前端代理 server { listen 80; server_name web.jt.com; location / { root dist; index index.html; } }
重启nginx
package com.jt.controller; @RestController @CrossOrigin public class PortController { //动态获取端口号 @Value("${server.port}") private Integer port; @GetMapping("/getPort") public String getPort(){ return "当前端口号:"+port; } }
命令: java -jar 8091.jar
#配置后端代理 server { listen 80; server_name manage.jt.com; location / { #proxy_pass 映射的是请求的地址 proxy_pass http://localhost:8091; } }
通过:http://manage.jt.com/itemCat/findItemCatList/3 测试后端域名是否可用