1. 学习计划

1、图片服务器

2、图片服务器安装

3、图片服务器的使用

4、图片上传功能

5、富文本编辑器的使用方法

6、商品添加功能实现

2. 图片服务器

1、存储空间可扩展。

2、提供一个统一的访问方式。

使用FastDFS,分布式文件系统。存储空间可以横向扩展,可以实现服务器的高可用。支持每个节点有备份机。

2.1. 什么是FastDFS?

FastDFS是用c语言编写的一款开源的分布式文件系统。FastDFS为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。

2.2. 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分为多个组,每个组之间保存的文件是不同的。每个组内部可以有多个成员,组成员内部保存的内容是一样的,组成员的地位是一致的,没有主从的概念。

2.3. 文件上传的流程

客户端上传文件后存储服务器将文件ID返回给客户端,此文件ID用于以后访问该文件的索引信息。文件索引信息包括:组名,虚拟磁盘路径,数据两级目录,文件名。

组名:文件上传后所在的storage组名称,在文件上传成功后有storage服务器返回,需要客户端自行保存。

虚拟磁盘路径:storage配置的虚拟路径,与磁盘选项store_path*对应。如果配置了store_path0则是M00,如果配置了store_path1则是M01,以此类推。

数据两级目录:storage服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据文件。

文件名:与文件上传时不同。是由存储服务器根据特定信息生成,文件名包含:源存储服务器IP地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息。

2.4. 文件下载

2.5. 最简单的FastDFS架构

3. 图片服务器安装

3.1. 安装步骤

第一步:把图片服务器解压缩。

第二步:把图片服务器添加到Vmware中。

第三步:Vmware的网络配置。

第四步:开机

移动:网络配置不发生变化。要使用图片服务器,需要保证网络配置不变。

复制:重新生成一块网卡mac地址是新地址。

Ip地址:192.168.25.133

用户名root

密码:itcast

命令:startx进入图形界面

4. 图片服务器使用

4.1.导入工程

4.2.把项目安装到本地仓库

4.3.导入依赖到web工程中

<dependency>
<groupId>fastdfs_client</groupId>
<artifactId>fastdfs_client</artifactId>
<version>1.25</version>
</dependency>

4.4. 上传图片

4.4.1. 上传步骤

1、加载配置文件,配置文件中的内容就是tracker服务的地址。

配置文件内容:tracker_server=192.168.25.133:22122

2、创建一个TrackerClient对象。直接new一个。

3、使用TrackerClient对象创建连接,获得一个TrackerServer对象。

4、创建一个StorageServer的引用,值为null

5、创建一个StorageClient对象,需要两个参数TrackerServer对象、StorageServer的引用

6、使用StorageClient对象上传图片。

7、返回数组。包含组名和图片的路径。

4.4.2. 创建一个cilent.cnof文件

4.4.3. 代码

    @Test
public void testUpload() throws Exception {
//创建一个配置文件。文件名任意。内容就是tracker服务器的地址。
//使用全局对象加载配置文件。
ClientGlobal.init("E:/javaee_workspace/e3-manager-web/src/main/resources/conf/client.conf");
//创建一个TrackerClient对象
TrackerClient trackerClient = new TrackerClient();
//通过TrackClient获得一个TrackerServer对象
TrackerServer trackerServer = trackerClient.getConnection();
//创建一个StrorageServer的引用,可以是null
StorageServer storageServer = null;
//创建一个StorageClient,参数需要TrackerServer和StrorageServer
StorageClient storageClient = new StorageClient(trackerServer, storageServer);
//使用StorageClient上传文件。
String[] strings = storageClient.upload_file("‪E:/Users/lwb/Pictures/玫瑰花.jpg", "jpg", null);
for (String string : strings) {
System.out.println(string);
} }

4.5. 使用工具类上传

4.5.1. 导入依赖到common工程

<dependency>
<groupId>fastdfs_client</groupId>
<artifactId>fastdfs_client</artifactId>
<version>1.25</version>
</dependency>

4.5.2. 导入工具类

package cn.e3mall.common.utils;

import org.csource.common.NameValuePair;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.StorageClient1;
import org.csource.fastdfs.StorageServer;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer; public class FastDFSClient { private TrackerClient trackerClient = null;
private TrackerServer trackerServer = null;
private StorageServer storageServer = null;
private StorageClient1 storageClient = null; public FastDFSClient(String conf) throws Exception {
if (conf.contains("classpath:")) {
conf = conf.replace("classpath:", this.getClass().getResource("/").getPath());
}
ClientGlobal.init(conf);
trackerClient = new TrackerClient();
trackerServer = trackerClient.getConnection();
storageServer = null;
storageClient = new StorageClient1(trackerServer, storageServer);
} /**
* 上传文件方法
* <p>Title: uploadFile</p>
* <p>Description: </p>
* @param fileName 文件全路径
* @param extName 文件扩展名,不包含(.)
* @param metas 文件扩展信息
* @return
* @throws Exception
*/
public String uploadFile(String fileName, String extName, NameValuePair[] metas) throws Exception {
String result = storageClient.upload_file1(fileName, extName, metas);
return result;
} public String uploadFile(String fileName) throws Exception {
return uploadFile(fileName, null, null);
} public String uploadFile(String fileName, String extName) throws Exception {
return uploadFile(fileName, extName, null);
} /**
* 上传文件方法
* <p>Title: uploadFile</p>
* <p>Description: </p>
* @param fileContent 文件的内容,字节数组
* @param extName 文件扩展名
* @param metas 文件扩展信息
* @return
* @throws Exception
*/
public String uploadFile(byte[] fileContent, String extName, NameValuePair[] metas) throws Exception { String result = storageClient.upload_file1(fileContent, extName, metas);
return result;
} public String uploadFile(byte[] fileContent) throws Exception {
return uploadFile(fileContent, null, null);
} public String uploadFile(byte[] fileContent, String extName) throws Exception {
return uploadFile(fileContent, extName, null);
}
}

4.5.3. 测试

    @Test
public void testFastDfsClient() throws Exception {
FastDFSClient fastDFSClient = new FastDFSClient("E:/javaee_workspace/e3-manager-web/src/main/resources/conf/client.conf");
String string = fastDFSClient.uploadFile("E:/Users/lwb/Pictures/玫瑰花.jpg");
System.out.println(string);
}

5. 图片上传功能

5.1. 功能分析

使用的是KindEditor的多图片上传插件。

KindEditor 4.x 文档

http://kindeditor.net/doc.php

请求的url:/pic/upload

参数:MultiPartFile uploadFile

返回值:

可以创建一个pojo对应返回值。可以使用map

业务逻辑:

1、接收页面传递的图片信息uploadFile

2、把图片上传到图片服务器。使用封装的工具类实现。需要取文件的内容和扩展名。

3、图片服务器返回图片的url

4、将图片的url补充完整,返回一个完整的url。

5、把返回结果封装到一个Map对象中返回。

1、导入文件上传依赖到web工程中。

<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
</dependency>

2、新建resource.properties

IMAGE_SERVER_URL=http://192.168.25.133/

3、在springmvc.xml加载配置文件

 <!-- 加载配置文件 -->
<context:property-placeholder location="classpath:conf/resource.properties" />

4、在springmvc.xml配置多媒体解析器

<!-- 定义文件上传解析器 -->
<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>

5.2. controller

@Controller
public class PictureController { @Value("${IMAGE_SERVER_URL}")
private String IMAGE_SERVER_URL; @RequestMapping("/pic/upload")
@ResponseBody
public Map fileUpload(MultipartFile uploadFile) {
try {
//1、取文件的扩展名
String originalFilename = uploadFile.getOriginalFilename();
String extName = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
//2、创建一个FastDFS的客户端
FastDFSClient fastDFSClient = new FastDFSClient("classpath:resource/client.conf");
//3、执行上传处理
String path = fastDFSClient.uploadFile(uploadFile.getBytes(), extName);
//4、拼接返回的url和ip地址,拼装成完整的url
String url = IMAGE_SERVER_URL + path;
//5、返回map
Map result = new HashMap<>();
result.put("error", 0);
result.put("url", url);
return result;
} catch (Exception e) {
e.printStackTrace();
//5、返回map
Map result = new HashMap<>();
result.put("error", 1);
result.put("message", "图片上传失败");
return result;
}
}
}

5.3. 解决浏览器兼容性的问题

KindEditor的图片上传插件,对浏览器兼容性不好。

使用@ResponseBody注解返回java对象,

Content-Type:application/json;charset=UTF-8

返回字符串时:

Content-Type:text/plan;charset=UTF-8

5.3.1 导入工具类

package cn.e3mall.common.utils;

import java.util.List;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; /**
* 淘淘商城自定义响应结构
*/
public class JsonUtils { // 定义jackson对象
private static final ObjectMapper MAPPER = new ObjectMapper(); /**
* 将对象转换成json字符串。
* <p>Title: pojoToJson</p>
* <p>Description: </p>
* @param data
* @return
*/
public static String objectToJson(Object data) {
try {
String string = MAPPER.writeValueAsString(data);
return string;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
} /**
* 将json结果集转化为对象
*
* @param jsonData json数据
* @param clazz 对象中的object类型
* @return
*/
public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
try {
T t = MAPPER.readValue(jsonData, beanType);
return t;
} catch (Exception e) {
e.printStackTrace();
}
return null;
} /**
* 将json数据转换成pojo对象list
* <p>Title: jsonToList</p>
* <p>Description: </p>
* @param jsonData
* @param beanType
* @return
*/
public static <T>List<T> jsonToList(String jsonData, Class<T> beanType) {
JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
try {
List<T> list = MAPPER.readValue(jsonData, javaType);
return list;
} catch (Exception e) {
e.printStackTrace();
} return null;
} }

5.3.2  修改controller

@Controller
public class PictureController { @Value("${IMAGE_SERVER_URL}")
private String IMAGE_SERVER_URL; @RequestMapping(value="/pic/upload", produces=MediaType.TEXT_PLAIN_VALUE+";charset=utf-8")
@ResponseBody
public String uploadFile(MultipartFile uploadFile) {
try {
//把图片上传的图片服务器
FastDFSClient fastDFSClient = new FastDFSClient("classpath:conf/client.conf");
//取文件扩展名
String originalFilename = uploadFile.getOriginalFilename();
String extName = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
//得到一个图片的地址和文件名
String url = fastDFSClient.uploadFile(uploadFile.getBytes(), extName);
//补充为完整的url
url = IMAGE_SERVER_URL + url;
//封装到map中返回
Map result = new HashMap<>();
result.put("error", 0);
result.put("url", url);
return JsonUtils.objectToJson(result);
} catch (Exception e) {
e.printStackTrace();
Map result = new HashMap<>();
result.put("error", 1);
result.put("message", "图片上传失败");
return JsonUtils.objectToJson(result);
}
}
}

KindEditor的多图片上传插件最后响应的content-type是text/plan格式的json字符串。兼容性是最好的。

6. 富文本编辑器的使用方法

6.1. 富文本编辑器介绍

KindEditor

http://kindeditor.net/

UEditor:百度编辑器

http://ueditor.baidu.com/website/

CKEditor

http://ckeditor.com/

纯js开发,跟后台语言没有关系。

6.2. 使用方法

第一步:在jsp中引入KindEditor的css和js代码。

第二步:在表单中添加一个textarea控件。是一个富文本编辑器的载体。类似数据源。

第三步:初始化富文本编辑器。使用官方提供的方法初始化。

第四步:取富文本编辑器的内容。

表单提交之前,把富文本编辑器的内容同步到textarea控件中。

7. 商品添加功能实现

7.1. 功能分析

请求的url:/item/save

参数:表单的数据。可以使用pojo接收表单的数据,要求pojo的属性和input的name属性要一致。

使用TbItem对象接收表单的数据。

TbItem item,String desc

返回值:

Json数据。应该包含一个status的属性。

可以使用E3Result,放到e3-common中。

业务逻辑:

1、生成商品id

实现方案:

a) Uuid,字符串,不推荐使用。

b) 数值类型,不重复。日期+时间+随机数20160402151333123123

c) 可以直接去毫秒值+随机数。可以使用。

d) 使用redis。Incr。推荐使用。

使用IDUtils生成商品id

2、补全TbItem对象的属性

3、向商品表插入数据

4、创建一个TbItemDesc对象

5、补全TbItemDesc的属性

6、向商品描述表插入数据

7、E3Result.ok()

7.2. Dao层

向tb_item, tb_item_desc表中插入数据

可以使用逆向工程

7.3. Service层

参数:TbItem item,String desc

业务逻辑:略,参加上面

返回值:E3Result

@Override
public E3Result addItem(TbItem item, String desc) {
// 1、生成商品id
long itemId = IDUtils.genItemId();
// 2、补全TbItem对象的属性
item.setId(itemId);
//商品状态,1-正常,2-下架,3-删除
item.setStatus((byte) 1);
Date date = new Date();
item.setCreated(date);
item.setUpdated(date);
// 3、向商品表插入数据
itemMapper.insert(item);
// 4、创建一个TbItemDesc对象
TbItemDesc itemDesc = new TbItemDesc();
// 5、补全TbItemDesc的属性
itemDesc.setItemId(itemId);
itemDesc.setItemDesc(desc);
itemDesc.setCreated(date);
itemDesc.setUpdated(date);
// 6、向商品描述表插入数据
itemDescMapper.insert(itemDesc);
// 7、E3Result.ok()
return E3Result.ok();
}

发布服务

7.4. 表现层

引用服务

Controller

请求的url:/item/save

参数:TbItem item,String desc

返回值:E3Result

@RequestMapping("/item/save")
@ResponseBody
public E3Result saveItem(TbItem item, String desc) {
E3Result result = itemService.addItem(item, desc);
return result;
}

 总结

问题:SEVERE: Servlet.service() for servlet [dispatcher] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause

解决:给报错的service注入@Autowired

SSM商城项目(四)的更多相关文章

  1. SSM商城项目(二)

    1. 学习计划 1.将工程改造为基于SOA架构 2.商品列表查询功能实现. 2. 将工程改造为SOA架构 2.1. 分析 由于商城是基于soa的架构,表现层和服务层是不同的工程.所以要实现商品列表查询 ...

  2. SSM商城项目(一)

    1. 学习计划 1.电商行业的背景. 2.宜立方商城介绍 3.宜立方商城的系统架构 a) 功能介绍 b) 架构讲解 4.工程搭建-后台工程 a) 使用maven搭建工程 b) 使用maven的tomc ...

  3. MVC4商城项目四:应用Bundle捆绑压缩技术

    从MVC4开始,我们就发现,项目中对Global.asax进行了优化,将原来在MVC3中使用的代码移到了[App_Start]文件夹下,而Global.asax只负责初始化.其中的BundleConf ...

  4. SSM商城项目(十)

    1.   学习计划 1.使用freemarker实现网页静态化 a)Freemarker的使用方法 b)Freemarker模板的语法 c)Freemarker整合springmvc 2.Active ...

  5. SSM商城项目(九)

    1.   学习计划 1.Activemq整合springMQ的应用场景 2.添加商品同步索引库 3.商品详情页面动态展示 4.展示详情页面使用缓存 2.   Activemq整合spring 2.1. ...

  6. SSM商城项目(八)

    1.   学习计划 1.solr集群搭建 2.使用solrj管理solr集群 3.把搜索功能切换到集群版 4.添加商品同步到索引库 2.   什么是SolrCloud SolrCloud(solr 云 ...

  7. SSM商城项目(七)

    1.   学习计划 1.Solr服务搭建 2.Solrj使用测试 3.把数据库中的数据导入索引库 4.搜索功能的实现 2.   Solr服务搭建 2.1. Solr的环境 Solr是java开发. 需 ...

  8. SSM商城项目(六)

    1.学习计划 1.Redis服务器搭建 2.Redis持久化 3.Redis集群搭建 4.Jedis 5.Solr服务器安装 2.Redis的安装 2.1. Redis的安装 Redis是c语言开发的 ...

  9. SSM商城项目(五)

    1.   学习计划 1.前台系统搭建 2.商城首页展示 3.Cms系统的实现 a)         内容分类管理 b)         内容管理 4.前台内容动态展示 2.   商城首页展示 2.1. ...

随机推荐

  1. java.math.*;(一)

    package com.test; /* Math类: java.lang.Math类中包含基本的数字操作,如指数.对数.平方根和三角函数. java.math是一个包,提供用于执行任意精度整数(Bi ...

  2. Python全栈之路----数据类型—字典

    字典:可变,一种key-value的数据类型 info = { 'stu1101' : 'TengLan Wu' , 'stu1102' : 'LongZe Luola' , 'stu1103' : ...

  3. 排序算法练习--JAVA(:内部排序:插入、选择、冒泡、快速排序)

    排序算法是数据结构中的经典算法知识点,也是笔试面试中经常考察的问题,平常学的不扎实笔试时候容易出洋相,回来恶补,尤其是碰到递归很可能被问到怎么用非递归实现... 内部排序: 插入排序:直接插入排序 选 ...

  4. [随笔][Life][咖啡][咖啡分类]

    转载自:https://www.chalook.net/doc/201607/4710.shtml

  5. oracle-pl/sql之三

    集合与记录 set serveroutput on create or replace package my_types authid definer is type my_rec is record ...

  6. 【转载】Ocelot网关的路由热更新

    调用API修改Ocelot的配置文件 May 11, 2018 | netcoreocelot | 410 阅读 Ocelot是一个基于.net core的开源webapi服务网关开源项目,功能比较强 ...

  7. keepalived 高可用配置

    下载地址:http://www.keepalived.org/software/keepalived-1.2.12.tar.gzht 安装方法:1. ./configure 可能出现的错误 !!! O ...

  8. 文件处理,三元操作符,seek()函数,迭代函数和列表解析,reduce函数

    1.文件读取方类型 r,r+,w,x,a, r,读文件 w,写文件,文件内容全部删除,并将新内容从第一行开始赋值 x,写文件,只有文件不存在,可写,文件存在,报错 a,在文件莫问追加信息 r+,w+, ...

  9. WIN7 WIN10赋予文件或者文件夹完全访问权限

    WIN7 WIN10赋予文件或者文件夹完全访问权限win7文件夹图标中多了一把小锁打不开文件夹怎么办?解决办法一:右击目录→取得管理员权限!该方法适用于win7旗舰版.解决办法二:添加everyone ...

  10. FreeBsd网络性能优化方案sysctl

    以下是阿盛的配置 sysctl net.inet.tcp.msl= sysctl net.inet.tcp.mssdflt= sysctl net.inet.tcp.minmss= sysctl ne ...