multipartfile上传文件_SpringCloud微服务架构实战使用分布式文件系统DFS

使用分布式文件系统 DFS

微服务应用使用分布式方式进行部署,并且有可能随时随地部署多个副本,所以必须有一个独立的文件系统来管理用户上传和使用的资源文件,包括图片和视频等。

在模块goods-web 的设计中,我们是使用FastDFS这个轻量级的分布式文件系统来设计的。如果使用云服务商提供的对象存储服务来设计,如OSS服务等,则可以参照服务提供商的使用说明,并结合本实例进行设计。

下面针对库存管理中,商品创建和编辑时使用的图片,实现在FastDFS上进行存储和管理的设计。

有关FastDFS的安装、集群构建和相关配置等,将在运维部署部分的相关章节中进行介绍。

6b21daa2fb81cf358e36ec4c33c6af67.png

分布式文件系统客户端开发

FastDFS 提供了Java语言使用的客户端开发包,但在Spring Boot中使用时还需要进行二次开发。为了简化开发过程,我们使用tobato在GitHub上开源的一个专为Spring Boot开发者提供的封装。

首先,在goods-web模块中,增加如下依赖引用:

com.github.tobatofastdfs-client1.26.4-RELEASE

然后,在模块的配置文件application.yml 中增加如下配置:

fdfs:soTimeout: 1501connectTimeout:601thumbImage:width: 150height: 150trackerList:- 192.168.1.214:22122-192.168.1.215:22122spring.jmx.enabled: falsefile.path.head:http://192.168.1.214:8080/

这个配置假设 FastDFS 的TrackerServer安装了两台服务器,它们的P地址分别为“192.168.1.214”和“192.168.1.215”,并且可以通过链接“http:/192.168.1.214:8080/”使用文件。

接着,在工程的启动文件中增加注解@Import和@EnableMBeanExport,即导入fastdfs-client的相关配置,代码如下所示:

@SpringBootApplication@EnableDiscoveryClient@EnableFeignClients (basePackages = "com.demo")@componentScan(basePackages = "com.demo")R Import(FdfsClientConfig.class)@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)public class GoodswebApplication {public static void main(String[]args) {SpringApplication.run (GoodsWebApplication.class, args);}}

为了确认上面的引用和配置都已经准备就绪,可以启动应用验证一下。如果启动应用正常,则说明上面的配置是正确的。

现在,我们就可以创建一个“FastefsClient”实现文件的上传功能了,代码如下所示:

@servicepublic class FastefsClient {@Autowiredprotected FastFileStorageClient storageClient;public String uploFile (MultipartFile file){String fileType=FilenameUtils.getExtension(file.get0riginalFilename ()).toLowerCase();StorePath path =null;try {path = storageclient.uploadFile(file.getInputstream(),file.getsize(, fileType, nul1);Jcatch (IOException e){e.printstackTrace();}if(path !=null) {return path.getFu1lPath(;}else {return null;}public string uploile(Inputstream inputstream,Long size, String type)(StorePath path = null;try {path = storageclient.uploadFile(inputStream, size, type, null);}catch(Exception e){e.printStackTrace();}if(path!=null) {return path. getFullPath();}else ireturn null;public boolean deleteFile(string fullPath)try {storageClient.deleteFile(fullPath);return true;}catch(Exception e){e-printstackTrace(;}return false;}}

这里,设计了一个多态的uploFile方法,可以使用不同的参数通过调用FastFileStorageClient实现文件上传,同时设计了一个deleteFile方法,实现文件的删除操作。

商品图片上传设计

商品图片上传步骤如下。

首先,设计一个控制器PicUtilController;然后,在这个控制器中实现文件上传的功能,代码如下所示:

@Controller@RequestMapping("/pic")public class PicUtilController {@value("${file.path.head:http://192.168.1.214:84/}")private String pathHead;GAutowiredprivate FastefsClient fastefsClient;//可缩放图片上传CRequestMapping ("/upload")public String upload() {return "pic/upload-pic";}/*★*上传图片* @return大/@RequestMapping(value = "/uploadPic", method =RequestMethod. POST)public void uploadPic(@RequestParam ("pictureFile") MultipartFilemultipartFile,HttpServletRequest request,HttpServletResponse response)try{String filename = fastefsclient.uploFile (multipartFile);Long shopid =1L;AsyncThreadPool.getInstance().execute(new Runnable()(Goverridepublic void run(){try{savePic(multipartFile, filename ,shopid);]catch (Exception e){e.printStackTrace();});BufferedImage image = ImageIO.read(multipartFile.getInputStream());Map data = new HashMap();data.put("pathInfo", pathHead+filename);data.put("width", image.getWidth());data.put ("height", image.getHeight());ObjectMapper mapper = new ObjectMapper();String ret = mapper.writeValueAsString(data);response.setContentType("text/html; charset=utf8");response.getOutputStream().write(ret. getBytes());response.flushBuffer();}catch (IOException e){e.printStackTrace();}}...}

这个控制器设计了一个链接“/upload”,用来打开上传文件的操作界面。另外,另一个链接“/uploadPic”通过调用前面设计的文件客户端“FastefsClient”实现文件上传。上传后再将图片的路径和文件大小等信息返回给调用者。

在上面的代码中,文件上传的操作界面在视图设计“upload-pic.html”(源代码文件代码行30~33行)中实现,主要使用一个“input”控件从操作者的机器上选取文件进行上传,代码如下所示:

//点击上传

通过“upload-page.,js”(源代码文件代码行432~437行)设计一个文件上传的请求方法,即可在视图界面上调用上面的控制器设计中上传文件的链接“/uploadPic”了。调用成功后再取出文件信息,代码如下所示:

//上传图片function ajaxFileUpload(id){var url = '/pic/uploadPic';$.ajaxFileUpload({url :url,//需要链接到服务器地址fileElementId : id, //文件选择框的id属性dataType : 'json',//服务器返回的格式,可以是jsonsuccess:function(data){if(data.errorMsg){showMsg(data.errorMsg,"错误");}else{page.upload.finish(data.pathInfo, data.width, data.height);}}}};}

通过上述方法获取到文件信息之后,再通过“upload-pic.html”(源代码文件代码行53~80行)视图展现出来,这部分的设计代码如下所示:

选择图片后可以在下框中调整您所需的部分。
上传图片后预览

上面的设计完成后,最后显示的效果如图7-5所示。

ab88b8fe5e832336ab100980ba483fdd.png

其中,在进行图片选取时,还可以对图片进行裁剪,有关这部分的功能请查看项目的源代码。

注意,在进行上面的整个调试时,必须保证有分布式文件系统服务可以访问。

富文本编辑器上传图片设计

在库存管理中,对商品内容的编辑建议使用富文本编辑器,这样可以编辑出图文并茂的内容。使用富文本编辑器上传图片的原理与7.7.2节中的图片上传的设计基本相同。

这里以使用开源的ueditor富文本编辑器为例进行说明。

在控制器PicUtilController的设计中,使用如下所示的uploadimg方法设计:@controller@RequestMapping("/pic")public class PicUtilController {evalue("${file.path.head:http://192.168.1.214:84/}")private String pathHead;@Autowiredprivate FastefsClient fastefsClient;//ueditor 图片上传@RequestMapping (value = "/uploadimg", method= RequestMethod. POST,produces="text /html; charset=UTE-8")public void uploadimg(CRequestParam ( "upfile") MultipartFile upfile,HttpServletRequest request,HttpServletResponse response){try {String filename= fastefsclient. uploFile(upfile);Long shopid =1L;AsyncThreadPool.getInstance() .execute(new Runnable(){coverride .public void run() {try {savePic(upfile,filename , shopid);}catch(Exception e){e-printStackTrace();}}}};Map data = new HashMap();data.put ("original",upfile.getOriginalFilename());data.put("url",pathHead+filename);data.put("title","");data.put ("state", "sUCCESS");ObjectMapper mapper =new 0bjectMapper();String ret = mapper.writevalueAsString (data);response.setContentType ("text/html; charset=utf8");response.getOutputStream().write(ret.getBytes());response.flushBuffer(;}catch (Exception e){e.printStackTrace();}}}

与商品图片上传设计不同的地方是返回参数有点不一样,主要是根据ueditor插件的需要进行调整和设定。

在新增商品new.html和编辑商品edit.html的页面上增加如下所示代码,引用ueditor插件:

最后,必须在ueditor 插件的配置文件“editor_config.js”(源代码文件代码行38~41行)中,更改如下所示的几行配置:

//图片上传配置区, imageUrl: " /pic/uploadimg"//图片上传提交地址, imagePath:""//图片修正地址,引用了fixedImagePath,如有特殊需求,可自行配置,imageFieldName: "upfile"//图片数据的 key,若此处修改,需要在后台对应文件修改对应参数

这样,就可以使用富文本编辑器上传图片文件了。

设计完成后,显示的效果如图7-6所示。

c2257cdf9966c2b86f10b13f63a03275.png

建立本地文件信息库

当一个文件上传之后,为了方便以后可以继续使用这个文件,我们可以在本地建立一个文件信息库,用来保存一个文件的简要信息。实现方法如下。

首先,有关数据服务的设计部分在模块goods-restapi 中。本地信息的图片数据对象:

@Table(name = "t picture")@Datapublic class Picture{@Id@Generatedvalue(strategy =GenerationType.IDENTITY)private Long id;//图片编号@column(name = "path info")private String pathInfo;//文件路径Ccolumn(name = "file name")private String fileName;//文件名private int width;//宽度private int height;//高度private String flag;//标志@DateTimeFormat (pattern = "yyyy-MM-dd HH:mm:ss")ecolumn (name = "created",columnDefinition = "timestamp defaultcurrent_timestamp")@Temporal (TemporalType.TIMESTAMP)private Date created;//创建时间private Long merchantid;//商家编号}

对应的数据库表结构t _picture的定义:

CREATE TABLE 'tpicture'('id' bigint (20) NOT NULL AUTO_INCREMENT,'created'timestamp NOT NULL DEFAULT CURRENT TIMESTAMP,'file_name' varchar(255)COLLATE utf8 bin DEFAULT NULL,'flag'varchar(255)COLLATE utf8 bin DEFAULT NULL,'height' int(11) DEFAULT NULL,'merchantid' bigint (20) DEFAULT NULL,'path info' varchar(255)COLLATE utf8_bin DEEAULT NULL,'width' int(11) DEFAULT NULL,PRIMARY KEY ('id')ENGINE=InnoDB AUTO INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

有关本地图片信息库的数据服务部分的实现,可以参照商品数据服务的设计方法,不再赘述。成功上传文件之后,如何将文件的路径和简要信息保存到本地文件信息库中呢?

文件信息保存在控制器PicUtilController 的savePic方法中,代码如下所示:

@controller@RequestMapping("/pic")public class PicUtilController {Value("${file.path.head:http://192.168.1.214:84/}")private string pathHead;CAutowiredprivate PictureRestService pictureRestService;private String savePic(MultipartFile multipartFile,String filename,Longshopid) throws Exception{BufferedImage image = ImageI0.read (multipartFile.getInputStream ());PictureQo picture= new PictureQ0();picture.setFileName (filename);picture.setHeight (image. getHeight ());picture.setWidth(image.getwidth());picture.setPathInfo(pathHead);picture.setMerchantid(shopid);return pictureRestService.create(picture);}}

在使用了本地文件信息库之后,在库存管理中创建和编辑商品时就可以使用已经上传的文件了。

为了能够更好地使用本地文件信息库,我们需要在控制器PicUtilController中创建一个分页查询本地文件信息库的方法 listPic,代码如下所示:

@controller@RequestMapping("/pic")public class PicUtilController{@value("${file.path.head:http://192.168.1.214:84/}")private String pathHead;@Autowiredprivate PictureRestService pictureRestService;@RequestMapping(value = "/listPic",method = RequestMethod.POST)@ResponseBodypublic Page>listPic(PictureQo pictureQo){String json = pictureRestService.findPage (pictureQo);Gson gson = TreeMapConvert.getGson();TreeMap page = gson.fromJson(json,new TypeToken>(){}.getType());Pageable pageable = PageRequest.of(pictureQo.getPage(),pictureQo.getSize( , null);java.util.List list = new ArrayList<>();if(page != null && page.get ("list") !=null) {list = gson.fromJson (page.get ("list").toString(), newTypeToken>() {}.getType());String count - page.get( "total").toString();return new PageImpl(list, pageable,new Long ( count));}}

其中,控制器使用链接“/listPic”为页面设计提供调用方法,返回本地文件信息的分页列表。

在页面上使用脚本定义upload-page.,js(源代码文件代码行501~525行),实现文件信息库分页查询结果的处理方法,代码如下所示:

function getDataHtml (pageNo, pagesize) {$.ajax(iurl: "/pic/listPic",dataType: "json",type: "POST",cache: false,data: {page: pageNo-1,size: pagesize ll 8},success:function (data){var $list =$('#upload-list').empty();$.each (data.content, function (i, v) {var html ="";html +='
'+'
'+'

'+v.width+'x'+ v.height+'

'+'
';$list.append($ (html));})page.photos.setPosition(;document.getElementById('pagebar').innerHTML=PageBarNumList.getPageBar (data.number+1, data.totalPages,3,'getDataHtml',pagesize ll8,true);},errOr: function (e) {}});}

设计完成之后,展示的效果如图7-7所示。

dce47d9d0278b395e39e25d060c20cd4.png

总体测试

在库存管理项目整体开发完成之后,可以进行一个总体测试。这个测试需要调用类目管理的微服务接口,所以在进行测试时,可按下列顺序启动各个模块。

(1)启动类目接口服务:catalog-restapi模块。

(2)启动库存管理微服务API应用:goods-restapi模块。

(3)启动库存管理PC端Web应用:goods-web模块。

上面几个模块启动成功之后,可在浏览器打开如下链接地址:

http://localhost:8092

如果各个模块都能正常运行,则可以在库存管理首页中显示已有的商品列表,如图7-8所示。

297583a66f222fcd08e196521cb1cfdc.png

在这个页面中,我们可以新增或者编辑商品。编辑商品的操作界面如图7-9所示。

6766cfb4968609248668962e39f8b0d0.png

小结

本章介绍了库存管理的微服务接口和一个相关的Web应用微服务的开发。在这个项目的开发过程中,我们使用了半自动的数据库开发框架MyBatis,体验了与使用JPA不同的开发实践。在生产应用中,读者可以根据实际情况选择使用。

同时,本章的Web应用开发也演示了使用分布式文件系统的方法,不管是使用DFS,还是使用OSS,其设计思路和实现方法基本一致,所以我们只需掌握一种开发方法,就能够在实际应用中应用自如。

本文给大家讲解的内容

SpringCloud微服务架构实战:库存管理与分布式文件系统,使用分布式文件系统DFS、总体测试

  1. 下篇文章给大家讲解的是SpringCloud微服务架构实战:海量订单系统微服务开发;
  2. 觉得文章不错的朋友可以转发此文关注小编;
  3. 感谢大家的支持!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值