栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

图片管理应用

图片管理应用

文章目录
    • 一、简介
    • 二、父项目
    • 三、图片管理服务的数据库设计
    • 四、定义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


        
            
                org.springframework.boot
                spring-boot-dependencies
                2.2.5.RELEASE
                pom
                import
            
            
                org.apache.dubbo
                dubbo-spring-boot-starter
                2.7.5
            
            
            
                org.apache.curator
                curator-recipes
                4.3.0
            
            
            
                org.apache.curator
                curator-framework
                4.3.0
            
            
            
                com.github.pagehelper
                pagehelper-spring-boot-starter
                1.2.13
            
            
                org.mybatis.spring.boot
                mybatis-spring-boot-starter
                2.1.1
            
            
                cn.bestwu
                fastdfs-client-java
                1.27
            
            
                org.apache.commons
                commons-lang3
                3.9
            
        
    
三、图片管理服务的数据库设计
-- 创建图片表格
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


        
            com.bjsxt
            img_pojo
            1.0-SNAPSHOT
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
        
        
            mysql
            mysql-connector-java
        
    

com.bjsxt.img.mapper

package com.bjsxt.img.mapper;

import com.bjsxt.img.pojo.Image;

import java.util.List;


public interface ImageMapper {
    // 新增数据
    int insert(Image image);
    // 删除数据
    int deleteByPK(Long id);
    // 主键查询
    Image selectById(Long id);
    // 全数据查询
    List select();
}

ImageMapper.xml





    
        
        
        
        
        
        
    

    
        insert into img_manage(id, url, group_name, remote_file_name, origin_file_name, upload_time)
        values(DEFAULT, #{url}, #{groupName}, #{remoteFileName}, #{originFileName}, #{uploadTime})
    

    
        delete from img_manage
        where id = #{id}
    

    
        select id, url, group_name, remote_file_name, origin_file_name, upload_time
        from img_manage
    


application.yml

mybatis: # sql映射文件
  mapper-locations: classpath:mybatis/mapper/*.xml

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8
    username: root
    password: 1234
六、定义module : img_service_api

pom.xml


        
            com.bjsxt
            img_pojo
            1.0-SNAPSHOT
        
    

com.bjsxt.img.serviceapi

package com.bjsxt.img.serviceapi;

import com.bjsxt.img.pojo.Image;

import java.util.Map;


public interface ImageServiceAPI {
    // 新增图片
    int save(Image image);
    // 删除图片
    int remove(Long id);
    // 查看图片详情
    Image getById(Long id);
    // 分页查看图片信息,使用PageHelper实现分页。
    // 返回的结果是: {rows=[{图片对象}], total=总计图片数量, currentPage=当前页码, pages=总计页数, size=每页行数}
    Map getImages(int page, int rows);
}

七、module : img_service_provider

pom.xml


        
            org.springframework.boot
            spring-boot-starter
        
        
            org.apache.dubbo
            dubbo-spring-boot-starter
        
        
            org.apache.curator
            curator-recipes
        
        
            org.apache.curator
            curator-framework
        
        
            com.github.pagehelper
            pagehelper-spring-boot-starter
        
        
            com.bjsxt
            img_service_api
            1.0-SNAPSHOT
        
        
            com.bjsxt
            img_mapper
            1.0-SNAPSHOT
        
    

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  
public class ImageServiceImpl implements ImageServiceAPI {
    // 注入Mapper对象
    @Autowired
    private ImageMapper imageMapper;

    
    @Override
    @Transactional
    public int save(Image image) {
        return imageMapper.insert(image);
    }

    
    @Override
    @Transactional
    public int remove(Long id) {
        return imageMapper.deleteByPK(id);
    }

    
    @Override
    public Image getById(Long id) {
        return imageMapper.selectById(id);
    }

    
    @Override
    public Map getImages(int page, int rows) {
        // 使用分页查询
        PageHelper.startPage(page, rows);

        // 分页查询, 返回的结果是PageHelper封装的List的实现类型Page
        List list = imageMapper.select();

        // 使用PageInfo辅助工具对象,实现分页数据的获取
        PageInfo info = new PageInfo<>(list);

        // 创建返回结果
        Map 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_provider
  protocol:
    name: dubbo
    port: 20880
  registry:
    address: zookeeper://192.168.14.129:2181
  config-center:
    timeout: 10000
server:
  port: 8081
pagehelper:
  helper-dialect: mysql

启动zookeeper,启动ImageProviderApp

八、 定义module : imp_service_consumer

pom.xml


        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
        
            org.apache.dubbo
            dubbo-spring-boot-starter
        
        
            org.apache.curator
            curator-recipes
        
        
            org.apache.curator
            curator-framework
        
        
            cn.bestwu
            fastdfs-client-java
        
        
            org.apache.commons
            commons-lang3
        
        
            com.bjsxt
            img_service_api
            1.0-SNAPSHOT
        
    

application.yml

# FastDFS客户端配置
fdfs:
  connect-timeout: 10
  network-timeout: 30
  charset: UTF-8
  http:
    tracker_http_port: 8080
  tracker_server: 192.168.14.129:22122

dubbo:
  application:
    name: img_manage_consumer
  registry:
    address: zookeeper://192.168.89.140:2181

server:
  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);
        }
    }

    
    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;
        }
    }

    
    public byte[] downloadFile(String groupName, String fileName, NamevaluePair[] metaDatas){
        try{
            
            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
        }
    }

    
    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[] 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;


@Configuration
public class FastDFSAutoConfigure {

    
    @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;

    
    @Bean
    public 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 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;


@Service
public class ImageServiceImpl implements ImageService {

    // 注入远程服务代理对象。
    @Reference
    private ImageServiceAPI serviceAPI;

    @Override
    public int save(Image image) {
        return serviceAPI.save(image);
    }

    @Override
    public int remove(Long id) {
        return serviceAPI.remove(id);
    }

    @Override
    public Image getById(Long id) {
        return serviceAPI.getById(id);
    }

    @Override
    public Map 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 {

    @Autowired
    private ImageService imageService;
    @Autowired
    private FastDFSUtils utils;

    
    @GetMapping(value = {"/", "/index"})
    public String toIndex(@RequestParam(value = "page", defaultValue = "1") int page,
                          @RequestParam(value = "rows", defaultValue = "5") int rows,
                          Model model){
        // 调用服务逻辑,分页查询
        Map result = this.imageService.getImages(page, rows);
        // 查询结果使用请求作用域传递给页面。
        model.addAttribute("datas", result);
        return "index";
    }
}

index.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




    
    图片管理-上传图片
    
    
    
    


姓名:
图片:

图文:

完善功能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 {

    @Autowired
    private ImageService imageService;
    @Autowired
    private FastDFSUtils utils;

    
    @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 ;
        }
    }

    
    @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";
    }

    
    @PostMapping("/uploadImg")
    @ResponseBody
    public 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 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 map = new HashMap<>();
            map.put("message", "上传文件失败");
            map.put("error", 1);
            return map;
        }
    }

    
    @GetMapping("/toUpload")
    public String toUpload(){
        return "upload";
    }

    
    @GetMapping(value = {"/", "/index"})
    public String toIndex(@RequestParam(value = "page", defaultValue = "1") int page,
                          @RequestParam(value = "rows", defaultValue = "5") int rows,
                          Model model){
        // 调用服务逻辑,分页查询
        Map result = this.imageService.getImages(page, rows);
        // 查询结果使用请求作用域传递给页面。
        model.addAttribute("datas", result);
        return "index";
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/326391.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号