e3mall商城的归纳总结4之图片服务器以及文本编辑器
一、图片服务器
——1、认识图片服务器
大家可能都知道在分布式架构中使用图片上传可能会导致文件存放在某一个项目,而我们的项目基本上都采用集群的方式 ,因此这样会导致图片的问题比较难以存放,在这里我们有两个解决思路
a、开发时通过开发工具设置一个workspace(文件夹),让我们可以访问到该文件夹,然后把照片存入在其中,把图片名存放在数据库中。再通过tomcat访问该文件夹。当项目上线后可以通过nginx访问该文件夹。当然该方法适用于中小型项目,(开发流程跳转,日后再写一篇文章介绍)
b、使用图片服务器(本章重点)
使用FastDFS,分布式文件系统。存储空间可以横向扩展,可以实现服务器的高可用。支持每个节点有备份机。
——2、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分为多个组,每个组之间保存的文件是不同的。每个组内部可以有多个成员,组成员内部保存的内容是一样的,组成员的地位是一致的,没有主从的概念。
也就是说该服务器两个大模块Tracker server和Storage server。
Tracker server是领导,而Storage server是员工,当客户端发送请求时,要知道客户端是很重要的,所以需要领导来接待,领导接待后,肯定需要出去吃饭娱乐等^ _ ^ ,那么就需要员工去安排了.当然员工也需要每天每周像领导汇报自己的情况.大致流程用下图来表示
上传文件的保存路径规则为:
组名(storage)/虚拟磁盘号(store_path)/XX(目录)/XX(目录)/文件名.后缀名
——3、图片服务器的安装
这里图片服务器的安装较为困难,黑马那里只提供了VM虚拟机配置好的系统压缩文件.直接解压后导入到Vm虚拟机中就可以了。由于图片服务器的配置改较为麻烦,因此最好也是用黑马提供的ip地址:192.168.25.133
若使用该ip地址,必须将VM的区域网设置改成NAT模式。
可以有很多同学不太理解VM的三种虚拟网络(桥接模式、仅主机模式、NAT模式)
桥接模式:虚拟机ip地址需要与主机在同一个网段,网关、子网掩码都需要和主机一致。
NAT模式:虚拟机ip地址不和主机在同一个网段,虚拟机又开了一个网段,主机和虚拟机可以相互ping通(通过VMnet8). 也可以和外网ping通.
仅主机模式:虚拟机ip地址不和主机在同一个网段,虚拟机又开了一个网段,主机和虚拟机可以相互ping通.如果想上网,必须通过主机的虚拟网卡(VMnet1共享网络).
具体可查看我转载的文章:转到
注意:导入虚拟机后选择我已移动该虚拟机
移动:网络配置不发生变化。要使用图片服务器,需要保证网络配置不变。
复制:重新生成一块网卡mac地址是新地址。
二、前端访问url以及配置
url:/pic/upload
文本编辑器要求服务器回复的字段为
服务器上传图片需要在配置文件中添加上传解析器
<!-- 定义文件上传解析器 -->
<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层
//添加商品
@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();
}
三、作业
由于很多同学反应不会写留下的作业,因此作业这部分详细讲解一个逻辑步骤,逻辑为主,代码为辅。相信会给迷惑的你带来灵感的。
a、商品编辑
寻找前端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的内存数据)
b、商品删除
删除估计很多人都会,就更简单了.先找前端的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);
}
}
b、商品上下架
有同学问我上架下架啥意思,我也是欲哭无泪了.那我还是说一遍吧上架代表顾客用户可以通过商城首页看到该商品,下架就是代表该商品已经搜不到了(原因:商家质量问题、无库存等因素).但是可能以后还会上架。主要就是修改商品的属性。很简单!直接演示。
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();
}
再看看演示结果: