如何实现图片的上传-(上传到本地)

图片的上传以及Nginx的使用实现上传图片的回显

1.图片的上传:

图片上传使用的是easyUI的组件,并不是自己实现的.

实现图片上传的前提是配置了文件上传的解析器(applicationContext-mvc.xml):



    
      

1.1 前端的代码:

kingEditorParams : {
    filePostName  : "uploadFile",
    uploadJson : '/pic/upload',
    dir : "image"
},

这是前端common.js实现的封装的代码,当一点击开始上传的时候,就是访问的这个路径,会把图片发送给服务端(下面这张图是使用了Nginx反向代理之后实现的图片回显的效果)

如何实现图片的上传-(上传到本地)_第1张图片

当一点击开始上传之后,会把图片通过post请求发送给服务端,处理请求的路径是/pic/upload,文件上传的名字是uploadFile

1.2 服务端的实现:

FileController:具体的业务放在service层

@Controller
public class FileController {

    @Autowired
    private FileUploadService fileUploadService;


    @RequestMapping("/pic/upload")
    @ResponseBody
    public PicUploadResult uploadPic(MultipartFile uploadFile) {
        return fileUploadService.uploadPic(uploadFile);
    }
}

controller层接受请求的参数名字是uploadFile(这个是固定的,前端传过来的),参数的类型是MultipartFile,MultipartFile是一个接口,具体的类型是org.springframework.web.multipart.commons.CommonsMultipartFile,配置的文件上传解析器会将客户端传过来的文件解析成CommonsMultipartFile.

FileUploadService:

@Service

public class FileUploadServiceImpl implements FileUploadService {

/**
 * Spring容器如何动态的获取数据
 * @Value : 实现数据的动态获取
 * 说明:@value 注解可以直接为String或者基本类型赋值
 *     同时,可以利用spring的机制可以为array , list , mapp , set properties 赋值
 * 
 * 注意事项:
 *  1.在SSM框架中,该注解需要依赖@Service注解(Spring容器内部才能使用)  在Controller注解可能不好使
 *      SpringMVC容器  跟 Spring容器  是两个不同的容器
 *  2.如果使用SpringBoot则任何地方都能用
 */
@Value("${image.localDir}")
private String localDir;
@Value("${image.urlPre}")
private String urlPre;



@Override
public PicUploadResult uploadPic(MultipartFile uploadFile) { // 图片上传
    PicUploadResult result = new PicUploadResult();

    // 1.判断是否为图片 abc.jpg
    String fileName = uploadFile.getOriginalFilename();
    // 使用正则表达式进行判断
    if (!fileName.matches("^.*(jpg|png|gif)$")) { // . 代表任意的字符 * 代表有任意多个 的
        // 表示不是图片
        result.setError(1);
        return result;
    }

    try {
        /**
         * ImageIO是javax下面的一个工具类
         */
        // 2.判断是否为恶意程序 uploadFile.getInputStream() 文件流
        BufferedImage bufferedImage = ImageIO.read(uploadFile.getInputStream());
        // 3.获取图片宽度和高度 (图片宽高为 0 ,则图片是假的图片)
        int height = bufferedImage.getHeight();
        int width = bufferedImage.getWidth();
        if (height == 0 || width == 0) {
            result.setError(1); // 假图片
            return result;
        }
        // 4.准备文件存储的路径()
        // String localDir = "d:/file/"; // 本地文件夹
        // 5.实现分文件存储 yyyy/MM/dd 以 天 为单位 分文件
        String dateDir = new SimpleDateFormat("yyyy/MM/dd").format(new Date());
        // 6.形成保存图片的文件夹 d:/file/yyyy/MM/dd (文件存储的根目录)
        String picDir = localDir + dateDir;
        // 7.生成文件夹
        File picFile = new File(picDir); // 文件夹的文件执行
        if (!picFile.exists()) { // 文件夹不存在 就创建文件夹
            picFile.mkdirs();
        }
        // 8.重命名上传的文件名字 (避免重名)
        String uuid = UUID.randomUUID().toString().replace("-", ""); // asa22exac-adsfafadsf-3fddsfds
        // 生成随机数
        int randomNum = new Random().nextInt(999); // 生成随机数 (0-999)
        // 获取文件的后缀名
        String fileType = fileName.substring(fileName.lastIndexOf(".")); // .jpg
        // 拼文件名
        String realFileName = uuid + randomNum + fileType; // 真实的文件名称

        // 9生成文件的本地磁盘的路径 d:/file/yyyy/MM/dd/wqrwadasfiuoew800.jpg
        String localPath = picDir + "/" + realFileName;

        // 10实现文件的上传
        uploadFile.transferTo(new File(localPath));

        // 11添加文件的宽度,高度 需要返回
        result.setHeight(height + "");
        result.setWidth(width + "");

        // 12准备文件的虚拟路径
        // http://image.jt.com/file/2018/05/07/radweedwsaf210.jpg
        // String urlPre = "http://image.jt.com/";

        String urlPath = urlPre + dateDir + "/" + realFileName;
        result.setUrl(urlPath);
    } catch (IOException e) { // 不是图片会抛异常
        e.printStackTrace();
        result.setError(1); // 表示为恶意程序
        return result;
    }
    return result;
  }
}

分析:客户端上传文件,需要先判断上传的文件是不是图片,先使用正则表达式进行第一层过滤,如果正则的验证过了之后,但是可能是伪图片,所以还得使用ImageIO来将上传的文件进行转换成BufferedImage,如果转换失败,那么可能不是图片,转换成功之后,还得获取图片的宽,高,如果宽高任何一个为0,就说明转换之后不是图片,也就说明上传的不是图片.


如果这些验证都过了,说明上传的文件是图片,那么我们就需要将图片保存起来.由于上传的图片名字是固定的,而且保存的时候如果使用原始的图片名字的话,很可能
会出现名字冲突的问题,为了尽可能地避免重现保存图片出现冲突的问题,就需要服务端生产随机的名字,这里采用一种更安全的做法,先使用UUID生成一串随机数,
但是这种方式生成的随机数是根据时间戳来生成的(同一毫秒值生成的uuid随机数可能会一样),所以还得使用Randoom再生成随机的数字,将uuid生成的随机串
(去掉'-')加上生成的随机数字组成图片的名字,这种情况出现重名的概率比较小

注意拿到了图片文件之后,还需要将图片文件保存,所有的图片都保存在一个大的文件夹下(d:/file),但是这个文件夹路径是不能写死的,得用配置文件进行配置,还有
一点就是图片的回显需要一个虚拟的路径.图片上传之后,

如何实现图片的上传-(上传到本地)_第2张图片

图片的上传之后的回显是由easyUI来实现的,但是要求是从服务端返回个数据的页面的json数据是有要求的,

{"error":0,"url":"图片的保存路径","width":图片的宽度,"height":图片的高度}

参数说明: 0代表是一张图片,如果是0,前台才可以解析并显示。1代表不是图片,
不显示如果不设置宽度和高度,则默认用图片原来的大小,所以不用设置    

返回的就是 PicUploadResult

public class PicUploadResult {
    private Integer error=0;        //图片上传错误不能抛出,抛出就无法进行jsp页面回调,所以设置这个标识,0表示无异常,1代表异常
    private String url;
    private String width;
    private String height;
~~~ 此处省略get,set方法

这个返回的对象里面的url需要在服务端进行封装,封装的就是easyUI实现回显图片的虚拟路径,这个url是虚拟路径:

理解这个url(虚拟路径) : 图片有专门的图片服务器,图片的存储也是在专门的服务器里面,异常easyUI要进行图片的回显,就需要访问图片服务器.目前我们这个
项目保存图片是保存在d:file里面,目前的水平只能做到保存在本机(还做不到保存在别的服务器),但是做图片回显的时候,我们就希望模拟实现那种跨服务器的
图片访问(现在用的是同一台主机),所以返回的url是一个虚拟路径,http://image.jt.com/.这就相当于当图片回显时,访问的是这个域名下的图片.

为了实现程序的可扩展性,可以把两个变量写在配置文件里面,一个是localDir(图片保存的本地根目录),还有一个是urlPre(图片回显时需要访问的网址)

如何实现图片的上传-(上传到本地)_第3张图片

有了这个properties配置文件之后,好需要加载这个配置文件(在applicationContext里面进行加载)

    
        
        
            
            
                classpath:/properties/jdbc.properties
                classpath:/properties/image.properties
              
        
    

这样在service层就可以直接使用@Value()注解进行动态地赋值注入了

你可能感兴趣的:(JT-day06)