文章目录
- 一、简介
- 二、父项目
- 三、图片管理服务的数据库设计
- 四、定义module : img_pojo
- 五、定义module : img_mapper
- 六、定义module : img_service_api
- 七、module : img_service_provider
- 八、 定义module : imp_service_consumer
一、简介
内容:
实现一个图片管理应用。可以上传图片,查看图片,删除图片,下载图片。
技术:
SpringBoot:开发平台
Dubbo:远程服务调用技术
MyBatis:数据库访问
MySQL:数据库
Zookeeper:Dubbo的注册中心
FastDFS:集中管理所有上传的图片
Nginx:为FastDFS中的Storage服务器,提供一个虚拟主机,就是可以在线使用浏览器查看Storage内的图片。
实现:
实体 - 定义module : img_pojo
module中定义需要的实体类型
数据访问 - 定义module : img_mapper
module中定义需要的数据访问接口和SQL映射文件。
服务标准 - 定义module : img_service_api
module中定义dubbo远程访问是的服务标准接口。只定义标准接口。
服务提供者 - 定义module : img_service_provider
module中实现img_service_api中的服务接口,并发布服务。在zk中发布服务信息。
服务消费者 - 定义module : imp_service_consumer
module中使用img_service_api中的接口,远程调用服务提供者给予的实现。
提供客户视图(UI)
提供图片上传|下载。 图片上传|下载不适合使用dubbo处理。
二、父项目
pom.xml
<dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.2.5.RELEASE</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>2.7.5</version></dependency><!-- 访问zookeeper的Java客户端应用 --><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.3.0</version></dependency><!-- 访问zookeeper的Java客户端应用 --><dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>4.3.0</version></dependency><!-- 分页 --><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.2.13</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.1</version></dependency><dependency><groupId>cn.bestwu</groupId><artifactId>fastdfs-client-java</artifactId><version>1.27</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.9</version></dependency></dependencies></dependencyManagement>
三、图片管理服务的数据库设计
-- 创建图片表格
create table img_manage(id bigint not null auto_increment comment '主键',url varchar(255) default '' comment '访问这个图片的HTTP地址',group_name varchar(64) default 'group1' comment 'FastDFS中的卷名',remote_file_name varchar(255) default '' comment 'FastDFS中的文件名,如:M00/00/00/abc.jpg',origin_file_name varchar(255) default '' comment '上传的图片的原始名称',upload_time date not null comment '上传图片的时间',primary key (id)
) comment '保存上传到FastDFS中的图片信息表';
四、定义module : img_pojo
public class Image implements Serializable {private Long id;private String groupName;private String remoteFileName;private String originFileName;private Date uploadTime;public String getUrl(){return groupName + "/" + remoteFileName;}public void setUrl(String url){// url属性为推导属性。url的值,是由groupName和remoteFileName组合得到。}//其他正常
五、定义module : img_mapper
pom.xml
<dependencies><dependency><groupId>com.bjsxt</groupId><artifactId>img_pojo</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency></dependencies>
com.bjsxt.img.mapper
package com.bjsxt.img.mapper;import com.bjsxt.img.pojo.Image;import java.util.List;/*** 图片数据访问接口。连接数据库MySQL实现数据CRUD操作。*/
public interface ImageMapper {// 新增数据int insert(Image image);// 删除数据int deleteByPK(Long id);// 主键查询Image selectById(Long id);// 全数据查询List<Image> select();
}
ImageMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjsxt.img.mapper.ImageMapper"><resultMap id="ImageMap" type="com.bjsxt.img.pojo.Image"><id property="id" column="id" /><result property="groupName" column="group_name" /><result property="remoteFileName" column="remote_file_name" /><result property="originFileName" column="origin_file_name" /><result property="uploadTime" column="upload_time" /><result property="url" column="url" /></resultMap><insert id="insert" keyProperty="id" useGeneratedKeys="true" keyColumn="id">insert into img_manage(id, url, group_name, remote_file_name, origin_file_name, upload_time)values(DEFAULT, #{url}, #{groupName}, #{remoteFileName}, #{originFileName}, #{uploadTime})</insert><delete id="deleteByPK">delete from img_managewhere id = #{id}</delete><select id="selectById" resultMap="ImageMap">select id, url, group_name, remote_file_name, origin_file_name, upload_timefrom img_managewhere id = #{id}</select><select id="select" resultMap="ImageMap">select id, url, group_name, remote_file_name, origin_file_name, upload_timefrom img_manage</select></mapper>
application.yml
mybatis: # sql映射文件mapper-locations: classpath:mybatis/mapper/*.xmlspring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8username: rootpassword: 1234
六、定义module : img_service_api
pom.xml
<dependencies><dependency><groupId>com.bjsxt</groupId><artifactId>img_pojo</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies>
com.bjsxt.img.serviceapi
package com.bjsxt.img.serviceapi;import com.bjsxt.img.pojo.Image;import java.util.Map;/*** 图片服务标准接口。* dubbo的Provider需要实现这个接口提供服务* dubbo的Consumer需要使用这个接口调用服务*/
public interface ImageServiceAPI {// 新增图片int save(Image image);// 删除图片int remove(Long id);// 查看图片详情Image getById(Long id);// 分页查看图片信息,使用PageHelper实现分页。// 返回的结果是: {rows=[{图片对象}], total=总计图片数量, currentPage=当前页码, pages=总计页数, size=每页行数}Map<String, Object> getImages(int page, int rows);
}
七、module : img_service_provider
pom.xml
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId></dependency><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId></dependency><dependency><groupId>com.bjsxt</groupId><artifactId>img_service_api</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>com.bjsxt</groupId><artifactId>img_mapper</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies>
com.bjsxt.img.service.impl
package com.bjsxt.img.service.impl;import com.bjsxt.img.mapper.ImageMapper;
import com.bjsxt.img.pojo.Image;
import com.bjsxt.img.serviceapi.ImageServiceAPI;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** 服务提供者, 实现服务标准。* 这个Service注解是dubbo的Service注解* @Transactional事务管理*/
@Service
public class ImageServiceImpl implements ImageServiceAPI {// 注入Mapper对象@Autowiredprivate ImageMapper imageMapper;/*** 新增图片到数据库* @param image 要新增的数据对象* @return*/@Override@Transactionalpublic int save(Image image) {return imageMapper.insert(image);}/*** 删除数据* @param id 要删除的数据主键* @return*/@Override@Transactionalpublic int remove(Long id) {return imageMapper.deleteByPK(id);}/*** 主键查询 * 注意:查询是只读的,不考虑 @Transactional* @param id 要查询的数据的主键* @return*/@Overridepublic Image getById(Long id) {return imageMapper.selectById(id);}/*** 分页查询* @param page 第几页* @param rows 多少行* @return*/@Overridepublic Map<String, Object> getImages(int page, int rows) {// 使用分页查询PageHelper.startPage(page, rows);// 分页查询, 返回的结果是PageHelper封装的List的实现类型PageList<Image> list = imageMapper.select();// 使用PageInfo辅助工具对象,实现分页数据的获取PageInfo<Image> info = new PageInfo<>(list);// 创建返回结果Map<String, Object> result = new HashMap<>();result.put("total", info.getTotal()); // 总计数据行数result.put("rows", list); // 当前页面的数据集合result.put("currentPage", page); // 当前是第几页result.put("pages", info.getPages()); // 总计多少页result.put("size", rows); // 每页显示多少行。return result;
}
}
启动类
com.bjsxt.img
package com.bjsxt.img;import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@EnableDubbo
@MapperScan(basePackages = {"com.bjsxt.img.mapper"})
public class ImageProviderApp {public static void main(String[] args) {SpringApplication.run(ImageProviderApp.class, args);}
}
application.yml
spring:profiles:active: db
dubbo:application: # dubbo应用必须提供一个唯一的命名。同名的dubbo应用自动组成集群。name: img_manage_providerprotocol:name: dubboport: 20880registry:address: zookeeper://192.168.14.129:2181config-center:timeout: 10000
server:port: 8081
pagehelper:helper-dialect: mysql
启动zookeeper,启动ImageProviderApp
八、 定义module : imp_service_consumer
pom.xml
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId></dependency><dependency><groupId>cn.bestwu</groupId><artifactId>fastdfs-client-java</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency><dependency><groupId>com.bjsxt</groupId><artifactId>img_service_api</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies>
application.yml
# FastDFS客户端配置
fdfs:connect-timeout: 10network-timeout: 30charset: UTF-8http:tracker_http_port: 8080tracker_server: 192.168.14.129:22122dubbo:application:name: img_manage_consumerregistry:address: zookeeper://192.168.14.129:2181server:port: 80
FastDFSUtils.java
package com.bjsxt.img.utils;import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;import java.util.Properties;public class FastDFSUtils {// 通过static初始化代码块,读取配置文件,初始化客户端连接对象。// 客户端连接对象,用于实现文件读写操作使用。private StorageClient storageClient;// 默认构造public FastDFSUtils() {// 提供默认配置Properties properties = new Properties();properties.setProperty("fastdfs.connect_timeout_in_seconds", "5");properties.setProperty("fastdfs.network_timeout_in_seconds", "30");properties.setProperty("fastdfs.charset", "UTF-8");properties.setProperty("fastdfs.http_tracker_http_port", "8080");properties.setProperty("fastdfs.tracker_servers", "localhost:22122");init(properties);}public FastDFSUtils(Properties properties) {init(properties);}public void init(Properties properties){try {// 读取配置文件,借助SpringBoot实现配置ClientGlobal.initByProperties(properties);// 创建Tracker客户端对象TrackerClient trackerClient = new TrackerClient();// 创建Tracker服务器对象TrackerServer trackerServer = trackerClient.getConnection();// 创建Storage服务器对象StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);// 创建Storage客户端对象storageClient = new StorageClient(trackerServer, storageServer);}catch(Exception e){e.printStackTrace();// 初始化代码块出错,一定要抛出错误,停止虚拟机。throw new ExceptionInInitializerError(e);}}/*** 文件删除,FastDFS会自动删除这个文件对应的metaData。就是文件名-m这个文件。*/public boolean deleteFile(String groupName, String fileName){try{// storageClient.delete_file(String groupName, String fileName);// groupName - 要删除的文件的卷名,就是保存文件的storage服务配置中的groupName// fileName - 要删除的文件的文件名,包含路径地址。格式:M00/目录/目录/文件名.后缀名// M00代表保存文件的目录, store_path0 。 目录/目录 - 保存文件的具体位置。int result = storageClient.delete_file(groupName, fileName);// 返回结果为0,代表删除成功,其他是删除失败。return result == 0;}catch(Exception e){e.printStackTrace();return false;}}/*** 文件下载* @param metaDatas - 传入一个数组,用于保存下载文件的扩展信息。如果传入null,则不需要文件扩展信息。* 如果传入的数组不是null,则需要文件的扩展信息。* @return 下载的文件内容*/public byte[] downloadFile(String groupName, String fileName, NameValuePair[] metaDatas){try{/** byte[] storageClient.download_file(String groupName, String fileName);* groupName - 卷名 | 组名* fileName - 文件名,是文件保存在fdfs中的目录和文件名。*/byte[] datas = storageClient.download_file(groupName, fileName);// 要下载的文件的扩展信息。if(metaDatas != null) {NameValuePair[] tmp = storageClient.get_metadata(groupName, fileName);// 把查询到的文件扩展信息。保存到传入的数组中。for(int i = 0; i < tmp.length; i++){metaDatas[i] = tmp[i];}}// 返回下载的文件内容return datas;}catch(Exception e){e.printStackTrace();return null; // 下载失败,返回null}}/*** 使用StorageClient对象,实现文件的上传。*/public String[] uploadFile(byte[] datas, String fileName, String authName){try{// 文件上传// 获取文件的扩展名String extName = fileName.substring(fileName.lastIndexOf(".") + 1);// 创建文件扩展信息。扩展信息包括文件的原始名称,文件的大小,文件的上传者姓名NameValuePair[] metaDatas = new NameValuePair[3];metaDatas[0] = new NameValuePair("fileName", fileName);metaDatas[1] = new NameValuePair("fileSize", datas.length+"");metaDatas[2] = new NameValuePair("auth", authName);/** String[] storageClient.upload_file(byte[] datas, String extName, NameValuePair[] metaDatas)* datas - 要上传的文件的内容* extName - 上传的文件的扩展名* metaDatas - 上传的文件的扩展信息是什么。 如:文件的原始名称、文件的容量大小、文件的上传者等。*/String[] result = storageClient.upload_file(datas, extName, metaDatas);// 上传成功,无异常。返回字符串数组。// 字符串数组长度为2。 0下标位置是 卷名|组名。 1下标位置是 文件名(目录/文件)// fdfs为了解决上传的文件原始名称冲突内容不冲突而覆盖的问题,存储文件的时候,会提供一个uuid文件名称。return result;}catch(Exception e){e.printStackTrace();return null; // 异常发生,返回null。代表上传失败。}}
}
FastDFS客户端工具类型需要使用的自动装配对象,用来创建工具类型的对象。
spring容器管理创建的工具类型的对象
package com.bjsxt.img.config;import com.bjsxt.img.utils.FastDFSUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.Properties;/*** FastDFS客户端工具类型需要使用的自动装配对象。* 用来创建工具类型的对象。*/
@Configuration
public class FastDFSAutoConfigure {/*** 依托SpringBoot配置文件特性,读取配置文件中配置的信息。*/@Value("${fdfs.connect-timeout}")private String connectTimeout;@Value("${fdfs.network-timeout}")private String networkTimeout;@Value("${fdfs.charset}")private String charSet;@Value("${fdfs.http.tracker_http_port}")private String trackerHttpPort;@Value("${fdfs.tracker_server}")private String trackerServer;/*** 创建工具类型的对象,spring容器管理* @return*/@Beanpublic FastDFSUtils fastDFSUtils(){// 根据SpringBoot配置文件,创建一个Properties对象。Properties properties = new Properties();properties.setProperty("fastdfs.connect_timeout_in_seconds", connectTimeout);properties.setProperty("fastdfs.network_timeout_in_seconds", networkTimeout);properties.setProperty("fastdfs.charset", charSet);properties.setProperty("fastdfs.http_tracker_http_port", trackerHttpPort);properties.setProperty("fastdfs.tracker_servers", trackerServer);// 构造工具类型对象。FastDFSUtils fastDFSUtils = new FastDFSUtils(properties);return fastDFSUtils;}}
服务接口ImageService
package com.bjsxt.img.service;import com.bjsxt.img.pojo.Image;import java.util.Map;/*** 本地的服务接口*/
public interface ImageService {// 保存图片, 新增int save(Image image);// 删除图片int remove(Long id);// 主键查询图片详情Image getById(Long id);// 分页查询图片信息Map<String, Object> getImages(int page, int rows);
}
服务接口ImageService的实现类
ImageServiceImpl
package com.bjsxt.img.service.impl;import com.bjsxt.img.pojo.Image;
import com.bjsxt.img.service.ImageService;
import com.bjsxt.img.serviceapi.ImageServiceAPI;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;import java.util.Map;/*** 本地服务实现。要成调用Provider提供的服务。还要实现图片的上传下载操作。*/
@Service
public class ImageServiceImpl implements ImageService {// 注入远程服务代理对象。@Referenceprivate ImageServiceAPI serviceAPI;@Overridepublic int save(Image image) {return serviceAPI.save(image);}@Overridepublic int remove(Long id) {return serviceAPI.remove(id);}@Overridepublic Image getById(Long id) {return serviceAPI.getById(id);}@Overridepublic Map<String, Object> getImages(int page, int rows) {return this.serviceAPI.getImages(page, rows);}
}
ImageController
package com.bjsxt.img.contoller;import com.bjsxt.img.pojo.Image;
import com.bjsxt.img.service.ImageService;
import com.bjsxt.img.utils.FastDFSUtils;
import org.csource.common.NameValuePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;
import java.awt.im.InputContext;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;/*** 图片服务的控制器。与客户直接交互。*/
@Controller
public class ImageController {@Autowiredprivate ImageService imageService;@Autowiredprivate FastDFSUtils utils;/*** 首页面跳转方法。 就是分页查询图片服务中所有可以管理的图片信息。* @param page 查询第几页, 默认第一页* @param rows 查询多少航,默认查五行* @param model 传递查询结果到视图。* {rows:[], total:, currentPage: pages, size}* @return 视图逻辑*/@GetMapping(value = {"/", "/index"})public String toIndex(@RequestParam(value = "page", defaultValue = "1") int page,@RequestParam(value = "rows", defaultValue = "5") int rows,Model model){// 调用服务逻辑,分页查询Map<String, Object> result = this.imageService.getImages(page, rows);// 查询结果使用请求作用域传递给页面。model.addAttribute("datas", result);return "index";}
}
index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head><meta charset="UTF-8"><title>图片管理-分页查看</title>
</head>
<body><div style="width: 800px; margin: auto; padding-top:50px; text-align: center"><a href="/toUpload">上传图片</a></div><div style="width: 800px; margin: auto; padding-top:50px; text-align: center"><table border="1"><caption>图片列表</caption><thead><tr><th>序号</th><th>卷名</th><th>文件原始名</th><th>上传时间</th><th>预览</th><th>操作</th></tr></thead><tbody><tr th:each="imageObj : ${datas.rows}"><th th:text="${imageObj.id}"></th><th th:text="${imageObj.groupName}"></th><th th:text="${imageObj.originFileName}"></th><th th:text="${#dates.format(imageObj.uploadTime, 'yyyy-MM-dd HH:mm:ss')}"></th><th><img style="height: 50px; padding:5px" th:src="@{'http://192.168.14.129:8888/' + ${imageObj.url}}"></th><th><a target="_blank" th:href="@{/download(id=${imageObj.id})}">下载</a><a th:href="@{/remove(id=${imageObj.id})}">删除</a></th></tr><tr><th colspan="6"><span th:text="${#strings.concat('总计', datas.total, '条')}"></span> <a th:if="${datas.currentPage} != 1" th:href="@{/index(page=${datas.currentPage-1},rows=${datas.size})}">上一页</a><a th:if="${datas.currentPage != datas.pages}" th:href="@{/index(page=${datas.currentPage+1},rows=${datas.size})}">下一页</a><span th:text="${#strings.concat('总计',datas.pages,'页')}"></span></th></tr></tbody></table></div>
</body>
</html>
启动类ImageConsumerApp
package com.bjsxt.img;import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@EnableDubbo
public class ImageConsumerApp {public static void main(String[] args) {SpringApplication.run(ImageConsumerApp.class, args);}
}
上传页面
upload.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>图片管理-上传图片</title><link src="/keditor/themes/default/default.css"><script src="/keditor/kindeditor-all-min.js"></script><script src="/keditor/lang/zh_CN.js"></script><script type="text/javascript">KindEditor.ready(function(K){var params = {uploadJson: 'uploadImg' // 上传图片地址};var editor = K.create("#content", params);K('#img_btn').click(function(){editor.loadPlugin("multiimage", function(){editor.plugin.multiImageDialog({"clickFn":function(list){var imgView = K("#img_view");imgView.html(""); // 清空视图内容K.each(list, function(i, n){imgView.append("<img src='"+n.url+"' style='height: 50px'/>");imgView.append("<input type='hidden' name='url' value='"+n.url+"'>");imgView.append("<input type='hidden' name='groupName' value='"+n.groupName+"'>");imgView.append("<input type='hidden' name='remoteFileName' value='"+n.remoteFileName+"'>");imgView.append("<input type='hidden' name='originFileName' value='"+n.originFileName+"'>");});editor.hideDialog(); // 隐藏上传图片插件}});});});});</script>
</head>
<body>
<div style="width: 800px; margin: auto; padding-top:50px; text-align: left"><form action="/saveImages" method="post">姓名:<input type="text" name="authName"><br>图片:<input type="button" id="img_btn" value="选择图片"><div id="img_view"></div><br>图文:<textarea id="content" name="content"></textarea><br><input type="submit" value="保存"></form>
</div>
</body>
</html>
完善功能ImageController
package com.bjsxt.img.contoller;import com.bjsxt.img.pojo.Image;
import com.bjsxt.img.service.ImageService;
import com.bjsxt.img.utils.FastDFSUtils;
import org.csource.common.NameValuePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;
import java.awt.im.InputContext;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;/*** 图片服务的控制器。与客户直接交互。*/
@Controller
public class ImageController {@Autowiredprivate ImageService imageService;@Autowiredprivate FastDFSUtils utils;/*** 下载图片* 1、 从数据库查询id对应的数据* 2、 根据查询结果到FastDFS中找文件数据* 3、 文件下载*/@GetMapping("/download")public void download(Long id, HttpServletResponse response){try {// 查询数据Image image = imageService.getById(id);// 从FastDFS中查询要下载的文件内容NameValuePair[] metaDatas = new NameValuePair[3];byte[] datas = utils.downloadFile(image.getGroupName(), image.getRemoteFileName(), metaDatas);// 使用响应输出流,向客户端输出文件内容,并提示下载。// 设置响应头为流输出response.setContentType("application/octet-stream");// 获取文件的原始名称String fileName = "";for (NameValuePair nvp : metaDatas) {if (nvp.getName().equals("fileName")) {fileName = nvp.getValue();}}// 编码处理,避免响应头设置的中文出现乱码。fileName = URLEncoder.encode(fileName, "UTF-8");// 设置响应头,并标记附件文件名为fileName。response.setHeader("content-disposition", "attachment;filename=" + fileName);// 输出文件内容到客户端response.getOutputStream().write(datas);// 刷新输出流缓冲。response.getOutputStream().flush();}catch(Exception e){e.printStackTrace();return ;}}/*** 删除图片数据* @param id* @return*/@GetMapping("/remove")public String remove(Long id){// 从数据库查询id对应的Image对象Image image = imageService.getById(id);int rows = imageService.remove(id); // 删除数据库中的数据if(rows == 1){// 删数据成功,需要从FastDFS中删除对应的图片utils.deleteFile(image.getGroupName(), image.getRemoteFileName());}return "redirect:/index?page=1&rows=5";}/*** 保存上传的图片信息到数据库*/@PostMapping("/saveImages")public String saveImages(String[] url, String[] groupName, String[] remoteFileName, String[] originFileName){if(url.length != groupName.length || url.length != remoteFileName.length || url.length != originFileName.length){// 参数个数不对。 不做任何操作,直接返回。return "redirect:/index?page=1&rows=5";}for(int i = 0; i < url.length; i++){// 循环新增图片对象数据,到数据库Image image = new Image();image.setGroupName(groupName[i]);image.setRemoteFileName(remoteFileName[i]);image.setOriginFileName(originFileName[i]);image.setUploadTime(new Date());this.imageService.save(image);}return "redirect:/index?page=1&rows=5";}/*** 处理图片上传方法。* 1、 上传文件到FastDFS* 2、 保存Image对象数据到数据库* @param filename 上传文件的原始名称* @param imgFile 上传的文件内容。*/@PostMapping("/uploadImg")@ResponseBodypublic Object uploadImg(String filename, @RequestParam("imgFile") MultipartFile imgFile){try {InputStream inputStream = imgFile.getInputStream();byte[] datas = new byte[inputStream.available()];inputStream.read(datas);// 上传文件String[] result = utils.uploadFile(datas,imgFile.getOriginalFilename(), "老金");Map<String, Object> map = new HashMap<>();map.put("url", "http://192.168.89.140:8888/"+result[0]+"/"+result[1]);map.put("error", 0);map.put("groupName", result[0]);map.put("remoteFileName", result[1]);map.put("originFileName", imgFile.getOriginalFilename());return map;}catch(Exception e){e.printStackTrace();Map<String, Object> map = new HashMap<>();map.put("message", "上传文件失败");map.put("error", 1);return map;}}/*** 跳转到上传图片页面* @return*/@GetMapping("/toUpload")public String toUpload(){return "upload";}/*** 首页面跳转方法。 就是分页查询图片服务中所有可以管理的图片信息。* @param page 查询第几页, 默认第一页* @param rows 查询多少航,默认查五行* @param model 传递查询结果到视图。* {rows:[], total:, currentPage: pages, size}* @return 视图逻辑*/@GetMapping(value = {"/", "/index"})public String toIndex(@RequestParam(value = "page", defaultValue = "1") int page,@RequestParam(value = "rows", defaultValue = "5") int rows,Model model){// 调用服务逻辑,分页查询Map<String, Object> result = this.imageService.getImages(page, rows);// 查询结果使用请求作用域传递给页面。model.addAttribute("datas", result);return "index";}
}