fastdfs分布式文件系统之与dubbo整合实现分布式服务接口

fastdfs是开源的轻量级分布式文件系统,它提供了java版本的client api。通过client API可以实现对文件的上传、追加、下载、删除等功能。

为了避免每个应用都配置fasdtfs参数、读取配置文件、调用client api获取trackerServer和StorageServer进行上传、下载、删除等操作及返回结果的

处理。所以采用与dubbo整合,提供分布式服务接口,来简化其它服务和应用的文件操作处理,同时提高代码的复用性。


1.总体结构

如图,总共分为fastdfs-api、fastdfs-consumer、fastdfs-provider三个工程。



fastdfs-api:对外提供的接口、dto的定义;

fastdfs-provider:调用fastdfs java client api对外提供的上传、下载、删除等接口实现以及对外暴露dubbo接口;

fastdfs-consumer:调用远程接口,测试上传、下载、删除功能;

其中fastdfs-consumer、fastdfs-provider需要依赖fastdfs-api的jar包。


2.fastdfs-api

对外提供的接口、dto的定义,下图是代码结构图:



从图中我们可以看到resultDto、UploadFileDto等dto。其中resultDto是上传、删除、下载返回结果dto,里面包含了结果状态、错误信息及文件地址等等信息。

UploadFileDto是上传文件时需传入的dto里面包含了文件的字节数组、文件后缀名、文件访问类型等等信息。

在enums包里面的LinkType是一个枚举类,定义连接类型。里面定义了内网访问和外网访问两个类型。

在exception包里面的AppException,内部异常类定义。

service包里面的CommonUploadFileService接口,里面定义了上传和删除功能的接口,代码如下:

/**
 * 
 * @ClassName: CommonUploadFileService
 * @Description: 公共文件上传业务逻辑层接口
 * @author mr_smile mr_smile@xxxx.com
 * 
 */
public interface CommonUploadFileService {
	/**
	 * 上传文件
	 * 
	 * @param uploadFileDto
	 *            上传文件dto
	 * @return
	 */
	public ResultDto uploadFile(UploadFileDto uploadFileDto)
			throws AppException;

	/**
	 * 删除远程文件
	 * 
	 * @param filePath
	 *            文件远程地址
	 * @return
	 */
	public void deleteFile(String filePath) throws AppException;

}

3.fastdfs-provider

调用fastdfs java client api对外提供的上传、下载、删除等接口实现以及对外暴露dubbo接口,在该工程中需要导入fastdfs-api的包。

代码结构如下图所示:


图中我们看到有exception、pool和impl等包及相关的配置文件。

包代码介绍:

在exception中,ERRORS枚举类主要是对在调用接口时可能出现的错误的定义,代码如下:

public enum ERRORS {

	PARAMETER_IS_NULL("21001", "必填参数为空", "必填参数为空"),

	FASTDFS_CONNECTION_FAIL("21002", "连接fastdfs服务器失败", "文件上传异常,请重试"),

	WAIT_IDLECONNECTION_TIMEOUT("21003", "等待空闲连接超时", "连接超时,请重试"),

	NOT_EXIST_GROUP("21004", "文件组不存在", "文件组不存在"),

	UPLOAD_RESULT_ERROR("21005", "fastdfs文件系统上传返回结果错误", "文件上传异常,请重试"),

	NOT_EXIST_PORTURL("21006", "未找到对应的端口和访问地址", "文件上传异常,请重试"),

	SYS_ERROR("21007", "系统错误", "系统错误"),

	FILE_PATH_ERROR("2108", "文件访问地址格式不对","文件访问地址格式不对"),

	DELETE_RESULT_ERROR("21009", "fastdfs文件系统删除文件返回结果错误", "文件删除异常,请重试"),

	NOT_EXIST_FILE("21010", "文件不存在", "文件不存在");

	/** 错误码 */
	String code;

	/** 错误信息,用于日志输出,便于问题定位 */
	String message;

	/** 错误提示,用于客户端提示 */
	String descreption;

	ERRORS(String code, String message) {
		this.message = message;
		this.code = code;
	}

	ERRORS(String code, String message, String descreption) {
		this.message = message;
		this.code = code;
		this.descreption = descreption;
	}

	public AppException ERROR() {
		return new AppException("FASTDFS", this.code, this.message,
				this.descreption);
	}

	public AppException ERROR(String descreption) {
		return new AppException("FASTDFS", this.code, this.message,
				descreption);
	}
}

pool包中的类主要实现连接池,提高程序的性能,在之前的代码中有所介绍。

impl包中的CommonUploadFileServiceImpl类上传和删除功能的接口的实现,代码如下:

/**
 * 公共上传文件服务接口实现类
 * 
 * @author mr_smile
 * 
 */
@Service("commonUploadFileService")
public class CommonUploadFileServiceImpl implements CommonUploadFileService {

	/** 日志 */
	private final Logger log = Logger
			.getLogger(CommonUploadFileServiceImpl.class);

	/** fastdfs工具类 */
	@Autowired
	private FastDfsUtil fastDfsUtil;

	/**
	 * 上传文件
	 * 
	 * @param uploadFileDto
	 *            上传文件dto
	 * @return
	 */
	@Override
	public ResultDto uploadFile(UploadFileDto uploadFileDto)
			throws AppException {

		/** 日志标识 */
		String logId = UUID.randomUUID().toString();
		log.info("[上传文件(uploadFile)][" + logId + "][prams:uploadFileDto="
				+ uploadFileDto.toString() + "]");

		try {

			/** 判断参数是否为空 */
			vlidParamIsNull(uploadFileDto, logId);

			/** 调用工具类上传 */
			ResultDto result = fastDfsUtil.upload(uploadFileDto);

			log.info("[上传文件(uploadFile)-返回结果][" + logId
					+ "][results:resultDto=" + result.toString() + "]");

			return result;

		} catch (AppException e) {

			log.error("[上传文件(uploadFile)][" + logId + "][异常:" + e + "]");
			throw e;

		}

	}

	/**
	 * 删除fastdfs服务器中文件
	 * 
	 * @param filePath
	 *            文件远程地址
	 * @return
	 */
	public void deleteFile(String filePath) throws AppException {

		/** 日志标识 */
		String logId = UUID.randomUUID().toString();
		log.info("[ 删除文件(deleteFile)][" + logId + "][parms:filePath="
				+ filePath + "]");
		try {
			if (StringUtils.isBlank(filePath)) {
				throw ERRORS.PARAMETER_IS_NULL.ERROR();
			}

			/** 解析文件路径 */
			String[] results = CommonUtils.parseFilePath(filePath, logId);

			/** 删除文件 */
			fastDfsUtil.deleteFile(results[0], results[1]);

		} catch (AppException e) {
			log.error("[ 删除文件(deleteFile)][" + logId + "][异常:" + e + "]");
			throw e;

		}
	}

	/**
	 * 
	 * @Description: 验证上传方法参数是否为空
	 * @param uploadFileDto
	 * @param logId
	 * 
	 */
	public void vlidParamIsNull(UploadFileDto uploadFileDto, String logId)
			throws AppException {

		log.info("[验证上传方法参数是否为空(vlidParamIsNull)][" + logId
				+ "][prams:uploadFileDto=" + uploadFileDto.toString() + "]");

		if (null == uploadFileDto || uploadFileDto.getFileBytes() == null
				|| null == uploadFileDto.getFileExtName()) {
			throw ERRORS.PARAMETER_IS_NULL.ERROR();
		}

	}
}


ServiceMainTest类设置dubbo参数及加载spring容器,代码如下:

/**
 * 
 * @ClassName: ServiceMainTest
 * @Description: TODO(这里用一句话描述这个类的作用)
 * @author mr_smile mr_smile@xxxxx.com
 * 
 */
public class ServiceMainTest {

	public static void main(String[] args) throws Exception {
		// 设在dubbo参数
		System.setProperty("dubbo.application.name", "dubbo-fastdfs");
		System.setProperty("dubbo.registry.address",
				"zookeeper://ip:2181");
		System.setProperty("dubbo.protocol.port", "8080");
		// 加载spring容器
		@SuppressWarnings("resource")
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
				"classpath:applicationContext-provider.xml");
		context.start();
		System.out.println("Press any key to exit.");
		System.in.read();
	}

}

配置文件介绍:

applicationContext-provider.xml:对外暴露接口

<import resource="classpath*:applicationContext.xml"/>
    <dubbo:protocol name="hessian"/>
	<dubbo:service ref="commonUploadFileService" interface="com.fastdfs.service.CommonUploadFileService" timeout="1200000"/>
	applicationContext.xml:对bean、参数文件的定义:
	<bean id="propertyConfigurer"
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations">
			<list>
				<value>classpath:property.properties</value>
			</list>
		</property>
	</bean>
	<bean name="connectionPool" class="com.fastdfs.pool.FastDfsUtil" init-method="init">
		<property name="minPoolSize" value="${minPoolSize}" />
		<property name="maxPoolSize" value="${maxPoolSize}" />
		<property name="waitTimes" value="${waitTimes}" />
	</bean>
	<!-- 具体的实现bean -->
	<context:annotation-config />
	<context:component-scan base-package="com.fastdfs.*" />


fastdfs_client.conf对fastdfs所需参数的定义:


connect_timeout = 10 
	network_timeout = 30 
	charset = UTF-8
	http.anti_steal_token = no
	tracker_server = ip1:22122,ip2:22122
	secret_key="";


property.properties对组、端口、访问地址、连接池等相关配置:


	#内网组名
INTRANET_GROUP=group2
#外网组名
OUTERNET_GROUP=group1
#虚拟访问地址
LINEK_URL=http://www.xxx.com
#内网端口
LINKE_INTRANET_PORT=800
#外网端口
LINKE_OUTERNET_PORT=801
#连接池最大连接数
maxPoolSize=30
#等待时间(单位:秒)
waitTimes=400
#连接池最小连接数
minPoolSize=20


4.fastdfs-consumer


调用远程接口,测试上传、下载、删除功能。


MainTest类测试调用远程dubbo接口进行上传,上传成功后,线程睡眠2秒后执行删除操作。代码如下:

public static void main(String[] args) {
		try {
			ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
					new String[] { "applicationConsumer.xml" });
			CommonUploadFileService commonUploadFileService = (CommonUploadFileService) context
					.getBean("commonUploadFileService");
			File file = new File("D:\\data\\1.jpg");
			UploadFileDto udto = new UploadFileDto();
			try {
				byte[] bytes = MainTest.getByte(file);
				udto.setFileBytes(bytes);
				udto.setFileExtName("jpg");
				udto.setLinkType(LinkType.INTRANET);
				//上传文件
				ResultDto dto = commonUploadFileService.uploadFile(udto);
				System.out.println("上传:filePath:" + dto.getFilePath());
				Thread.sleep(2000);
				//删除文件
				commonUploadFileService.deleteFile(dto.getFilePath());

			} catch (AppException e) {
				System.out.println(e.toString());
			} catch (Exception e) {
				e.printStackTrace();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public static byte[] getByte(File file) throws Exception {
		byte[] bytes = null;
		if (file != null) {
			InputStream is = new FileInputStream(file);
			int length = (int) file.length();
			if (length > Integer.MAX_VALUE) // 当文件的长度超过了int的最大值
			{
				System.out.println("this file is max ");
				return null;
			}
			bytes = new byte[length];
			int offset = 0;
			int numRead = 0;
			while (offset < bytes.length
					&& (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
				offset += numRead;
			}
			// 如果得到的字节长度和file实际的长度不一致就可能出错了
			if (offset < bytes.length) {
				System.out.println("file length is error");
				return null;
			}
			is.close();
		}
		return bytes;
	}
}


配置文件applicationConsumer.xml,需调用的远程接口bean的定义。配置如下:


  <dubbo:application name="consumer-of-helloworld-app" />      
      <!-- 使用multicast广播注册中心暴露发现服务地址    -->
  
    <dubbo:registry protocol="hessian" address="zookeeper://192.168.6.41:2181" timeout="60000" /> 

      <!-- 生成远程服务代理,可以和本地bean一样使用demoService -->   
    
    <dubbo:reference id="commonUploadFileService" interface="com.fastdfs.service.CommonUploadFileService" retries="0" timeout="100000"/>  
    <dubbo:reference id="commonDowenloadFileService" interface="com.fastdfs.service.CommonDownloadFileService" retries="0" timeout="60000"/>      
       

 
    </beans> 


在dubbo中默认使用的protocol为dubbo,在这种方式下,只能上传2M以内的文件,为了能解决传输大文件,那么需改为使用hessian协议。

上面的demo是全部是拷贝所有的jar包放入到工程里面的,在实际的开发中建议采用maven。hessian的依赖配置如下:


<dependency>
			<groupId>com.caucho</groupId>
			<artifactId>hessian</artifactId>
			<version>4.0.7</version>
		</dependency>
		<dependency>
			<groupId>org.mortbay.jetty</groupId>
			<artifactId>jetty</artifactId>
			<version>6.1.22</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.mortbay.jetty</groupId>
			<artifactId>jsp-2.1-jetty</artifactId>
			<version>6.1.22</version>
			<scope>provided</scope>
		</dependency>


注:所有代码已打包上传到我的资源库,有需要的可以前往下载。地址: http://download.csdn.net/detail/mr_smile2014/9629476









---------------------------------------------------------------------------版权声明-----------------------------------------------------------------------------------------------


版权声明:本文为博主原创文章,未经博主允许不得转载。本文地址:http://blog.csdn.net/mr_smile2014/article/details/52526065



  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值