你们可能都知道在分布式架构中使用图片上传可能会致使文件存放在某一个项目,而咱们的项目基本上都采用集群的方式 ,所以这样会致使图片的问题比较难以存放,在这里咱们有两个解决思路
a、开发时经过开发工具设置一个workspace(文件夹),让咱们能够访问到该文件夹,而后把照片存入在其中,把图片名存放在数据库中。再经过tomcat访问该文件夹。当项目上线后能够经过nginx访问该文件夹。固然该方法适用于中小型项目,(开发流程跳转,往后再写一篇文章介绍)
b、使用图片服务器(本章重点)
使用FastDFS,分布式文件系统。存储空间能够横向扩展,能够实现服务器的高可用。支持每一个节点有备份机。前端
FastDFS是用c语言编写的一款开源的分布式文件系统。FastDFS为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制, 并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。 FastDFS架构包括 Tracker server和Storage server。客户端请求Tracker server进行文件上传、下载, 经过Tracker server调度最终由Storage server完成文件上传和下载。 Tracker server做用是负载均衡和调度,经过Tracker server在文件上传时能够根据一些策略找到Storage server提供文件上传服务。 能够将tracker称为追踪服务器或调度服务器。 Storage server做用是文件存储,客户端上传的文件最终存储在Storage服务器上,Storage server没有实现本身的文件系统而是利用操做系统 的文件系统来管理文件。能够将storage称为存储服务器。
下面用图片来解释一下
服务端两个角色:
Tracker:管理集群,tracker也能够实现集群。每一个tracker节点地位平等。
收集Storage集群的状态。
Storage:实际保存文件
Storage分为多个组,每一个组之间保存的文件是不一样的。每一个组内部能够有多个成员,组成员内部保存的内容是同样的,组成员的地位是一致的,没有主从的概念。nginx
也就是说该服务器两个大模块Tracker server和Storage server。
Tracker server是领导,而Storage server是员工,当客户端发送请求时,要知道客户端是很重要的,因此须要领导来接待,领导接待后,确定须要出去吃饭娱乐等^ _ ^ ,那么就须要员工去安排了.固然员工也须要天天每周像领导汇报本身的状况.大体流程用下图来表示
上传文件的保存路径规则为:
组名(storage)/虚拟磁盘号(store_path)/XX(目录)/XX(目录)/文件名.后缀名web
这里图片服务器的安装较为困难,黑马那里只提供了VM虚拟机配置好的系统压缩文件.直接解压后导入到Vm虚拟机中就能够了。因为图片服务器的配置改较为麻烦,所以最好也是用黑马提供的ip地址:192.168.25.133
若使用该ip地址,必须将VM的区域网设置改为NAT模式。
能够有不少同窗不太理解VM的三种虚拟网络(桥接模式、仅主机模式、NAT模式)
桥接模式:虚拟机ip地址须要与主机在同一个网段,网关、子网掩码都须要和主机一致。
NAT模式:虚拟机ip地址不和主机在同一个网段,虚拟机又开了一个网段,主机和虚拟机能够相互ping通(经过VMnet8). 也能够和外网ping通.
仅主机模式:虚拟机ip地址不和主机在同一个网段,虚拟机又开了一个网段,主机和虚拟机能够相互ping通.若是想上网,必须经过主机的虚拟网卡(VMnet1共享网络).
具体可查看我转载的文章:转到
注意:导入虚拟机后选择我已移动该虚拟机
移动:网络配置不发生变化。要使用图片服务器,须要保证网络配置不变。
复制:从新生成一块网卡mac地址是新地址。redis
url:/pic/upload
文本编辑器要求服务器回复的字段为
服务器上传图片须要在配置文件中添加上传解析器spring
<!-- 定义文件上传解析器 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 设定默认编码 --> <property name="defaultEncoding" value="UTF-8"></property> <!-- 设定文件上传的最大值5MB,5*1024*1024 --> <property name="maxUploadSize" value="5242880"></property> </bean>
解决文本编辑器的乱码须要服务器返回text/plain类型字段
数据库
url:/item/save
前端的form表单中的name数据和Tb_item里的属性一致,所以用对象去接收数据,springmvc会自动把数据存到对象中,还有一个name=desc的商品描述。
所以再加上String desc参数
代码以下:
controller层json
//添加商品 @RequestMapping("/item/save") @ResponseBody public E3Result InsertItem(TbItem item, String desc) { return itemService.InsertItem(item, desc); }
service层数组
//添加商品 @Override public E3Result InsertItem(TbItem item, String desc) { final long id = IDUtils.genItemId(); //补齐数据 item.setId(id); //1-正常,2-下架,3-删除 item.setStatus((byte) 1); item.setCreated(new Date()); item.setUpdated(new Date()); TbItemMapper.insert(item); TbItemDesc itemDesc = new TbItemDesc(); itemDesc.setItemId(id); itemDesc.setItemDesc(desc); itemDesc.setCreated(new Date()); itemDesc.setUpdated(new Date()); itemDescMapper.insert(itemDesc); //返回e3Result对象,到前端进行解析 200表示添加成功 E3Result.ok()的状态就是200 return E3Result.ok(); }
因为不少同窗反应不会写留下的做业,所以做业这部分详细讲解一个逻辑步骤,逻辑为主,代码为辅。相信会给迷惑的你带来灵感的。tomcat
寻找前端url:/rest/page/item-edit
item-list.jsp中
后台controller:服务器
//返回商品编辑页面 @RequestMapping("/rest/page/item-edit") public String itemEdit() { return "item-edit"; }
返回商品编辑页面后页面自动加载商品规格和商品详情,这两个部分是经过两个get方式获取的。返回json对象仍是e3Result。
先看前端url:/rest/item/param/item/query/’+data.id
后台controller:
//返回商品的属性 @RequestMapping("/rest/item/param/item/query/{id}") @ResponseBody public String queryitem (@PathVariable Long id) { TbItem item = itemService.getItemByid(id); Editdata editdata = new Editdata(); editdata.setId(item.getId()); editdata.setParamData(item); E3Result e3Result = new E3Result(); e3Result.setData(editdata); return JsonUtils.objectToJson(e3Result); }
后台service经过逆向工程查询数据库的数据(此时能够先查redis,若redis没有,则查数据库,再把查到的数据存放到redis中。能够给商品设置一个TTl(expire属性),让热门商品第一次访问存到redis中,冷门商品不常常访问则丢失,有效的控制redis的内存数据)
删除估计不少人都会,就更简单了.先找前端的URL.
删除的URL:/rest/item/delete
controller层:
//批量删除商品 @RequestMapping("/rest/item/delete") @ResponseBody public E3Result deleteItems(Long[] ids) { itemService.deleteItems(ids); return E3Result.ok(); }
service层:
//商品删除 @Override public void deleteItems(Long[] ids) { //遍历数组而后删除 for (Long l : ids) { TbItemMapper.deleteByPrimaryKey(l); itemDescMapper.deleteByPrimaryKey(l); } }
有同窗问我上架下架啥意思,我也是欲哭无泪了.那我仍是说一遍吧上架表明顾客用户能够经过商城首页看到该商品,下架就是表明该商品已经搜不到了(缘由:商家质量问题、无库存等因素).可是可能之后还会上架。主要就是修改商品的属性。很简单!直接演示。
service层
//商品上架 @Override public void updateItems_S(Long[] ids) { for (Long l : ids) { TbItem item = new TbItem(); item.setId(l); //1-正常,2-下架,3-删除 item.setStatus((byte) 1); TbItemMapper.updateByPrimaryKeySelective(item); } } //商品下架 @Override public void updateItems_X(Long[] ids) { for (Long l : ids) { TbItem item = new TbItem(); item.setId(l); //1-正常,2-下架,3-删除 item.setStatus((byte) 2); TbItemMapper.updateByPrimaryKeySelective(item); } }
controller层
//批量上架商品 @RequestMapping("/rest/item/reshelf") @ResponseBody public E3Result status_shang(Long[] ids) { itemService.updateItems_S(ids); return E3Result.ok(); } //批量下架商品 @RequestMapping("/rest/item/instock") @ResponseBody public E3Result status_xia(Long[] ids) { itemService.updateItems_X(ids); return E3Result.ok(); }
再看看演示结果: