Dorado 7 : 21.3.2 准备后台服务

在前一节我们提到,使用了UploadAction的默认上传处理机制,需要设置上传路径,因此我们需要在dorado-home下的servlet-context.xml文件中,添加Bean的配置。双击打开servlet-context.xml,在配置文件中增加相关配置,最终代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <bean class="com.bstek.dorado.uploader.DefaultUploadProcessor">
        <property name="uploadDir" value="{webapp.home}/images/photo"></property>
    </bean>
</beans>

info

com.bstek.dorado.uploader.DefaultUploadProcessor即我们使用的默认上传处理类,此类为系统内置。
我们为其设置了文件上传保存路径,即WebContent/images/photo目录,上传路径支持3种类型表达式:
 
表达式
描述
{webapp.home}web应用的根目录,相当于ServletContext.getRealPath("/")
{webapp.tmpdir}web应用的缓存目录,相当于ServletContext.getAttribute("javax.servlet.context.tempdir")
{env:java.io.tmpdir}取java环境变量里的值,相当于System.getProperty("java.io.tmpdir")

注意:对于上传处理类的配置,一定要将配置信息放在servlet-context.xml中
DefaultUploadProcessor的源码如下:
package com.bstek.dorado.uploader;

import java.io.File;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.WebUtils;

public class DefaultUploadProcessor implements UploadProcessor,
        InitializingBean, ServletContextAware {

    private final static Logger logger = LoggerFactory
            .getLogger(DefaultUploadProcessor.class);

    protected String uploadDir;

    protected File _uploadFolder;

    protected ServletContext servletContext;

    public Object process(MultipartFile file, HttpServletRequest req,
            HttpServletResponse res) {

        String originalName = file.getOriginalFilename();
        String destFilename = generateName(_uploadFolder,
                originalName);
        File dest = new File(_uploadFolder, destFilename);
        logger.info("file:{} be saved to {}", originalName,
                dest.getAbsolutePath());
        try {
            FileUtils.copyInputStreamToFile(file.getInputStream(), dest);
        } catch (IOException e) {
            throw new UploaderException(e);
        }
        
        return destFilename;

    }

    protected String generateName(File folder, String originalName) {
        if (!new File(folder, originalName).exists()) {
            return originalName;
        }
        int i = 1, pointIdx = originalName.lastIndexOf('.');
        String prefix, suffix, newName;
        if (pointIdx == -1 || pointIdx == originalName.length()) {
            prefix = originalName;
            suffix = null;
        } else {
            prefix = originalName.substring(0, pointIdx);
            suffix = originalName.substring(pointIdx + 1);
        }

        do {
            if (suffix == null) {
                newName = String.format("%s_%d", prefix, i++);
            } else {
                newName = String.format("%s_%d.%s", prefix, i++, suffix);
            }

        } while (new File(folder, newName).exists());

        logger.info("file:{} renamed to {}", originalName, newName);

        return newName;
    }

    public void afterPropertiesSet() throws Exception {
        Assert.notNull(uploadDir);
        String parsedPath = parseUploadPath(uploadDir);
        logger.info("UploadDir:{}", parsedPath);
        _uploadFolder = new File(parsedPath);
        if (!_uploadFolder.exists()) {
            _uploadFolder.mkdirs();
        }
    }

    public String getUploadDir() {
        return uploadDir;
    }

    /**
     * 接受参数
     * 
     * ${webapp.home}/subdir
     * 
     * ${webapp.tmpdir}/subdir
     * 
     * ${env:java.io.tmpdir}/subdir
     * 
     * @param uploadDir
     */
    public void setUploadDir(String uploadDir) {
        this.uploadDir = uploadDir;
    }

    private String parseUploadPath(String uploadDir) {
        Pattern p = Pattern.compile("^(\\{(.*)\\})");
        Matcher m = p.matcher(uploadDir);
        if (m.find()) {
            String var = m.group(2);
            StringBuffer dirBuf = new StringBuffer();
            if (var.equals("webapp.home")) {
                m.appendReplacement(dirBuf, this.servletContext
                        .getRealPath("/").replaceAll("\\\\", "/"));
            } else if (var.equals("webapp.tmpdir")) {
                m.appendReplacement(dirBuf,
                        WebUtils.getTempDir(this.servletContext)
                                .getAbsolutePath().replaceAll("\\\\", "/"));
            } else if (var.startsWith("env:")) {
                m.appendReplacement(dirBuf, System
                        .getProperty(var.substring(4)).replaceAll("\\\\", "/"));
            } else {
                m.appendReplacement(dirBuf, m.group(0).replaceAll("\\\\", "/"));
            }
            m.appendTail(dirBuf);
            return dirBuf.toString();
        } else {
            return uploadDir;
        }
    }

    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }

}

可以看到这个默认处理类比较简单,可能在复杂的业务条件下并不适用,我们可以自定义一个类来可以实现UploadProcessor接口,范例代码如下:

public class MyUploadProcessor implements UploadProcessor {
  
    @Override
    public Object process(MultipartFile file, HttpServletRequest req,
            HttpServletResponse res) {
        //在这里简单的做个输出,在实际应用中可以做复杂的业务操作     
       	System.out.println("文件已经上传!!!");
        return null;
    }
}

在process方法中可以拿到file类,我们可以根据具体的项目需求来实现业务逻辑。

在servlet-context.xml中添加配置:

<bean class="com.bstek.dorado.sample.standardlesson.service.MyUploadProcessor" />