Spring:从messageConverter到大佬

文件上传 spring-mvc.xml 配置

应用是用的比较多的消息转换器

  • 一是 负责解析资源 <bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
  • 二是 负责解析Json <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">

此外若要进行文件的上传还要配置一个multipartResolver

  • 多媒体文件解析器 <bean id="multipartResolver"class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation=
               "http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context.xsd
                http://www.springframework.org/schema/mvc
                http://www.springframework.org/schema/mvc/spring-mvc.xsd
                http://www.springframework.org/schema/aop
                http://www.springframework.org/schema/aop/spring-aop.xsd">

    <context:component-scan base-package="zju.edu.als.controller"/>
    <!--扫描注解驱动,必须有-->
    <mvc:annotation-driven>
        <mvc:message-converters register-defaults="false"> <!-将默认的取消掉->
            <!-- 配置Spring的转换器 -->
            <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>text/plain;charset=UTF-8</value>
                    </list>
                </property>
            </bean>
            <bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
            <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
            <bean class="org.springframework.http.converter.xml.Jaxb2CollectionHttpMessageConverter"/>
            <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>application/json;charset=UTF-8</value>
                        <value>application/*+json;charset=UTF-8</value>
                        <value>text/json;charset=UTF-8</value>
                        <value>text/html;charset=UTF-8</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

    <!--内部资源视图解析器,当Controller下返回具体jsp文件名时,使其定位到具体的jsp文件-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>


    <aop:aspectj-autoproxy proxy-target-class="true"/>

    <!--添加 Shiro Spring AOP 权限注解的支持-->
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>


    <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- set the max upload size100MB -->
        <property name="maxUploadSize">
            <value>104857600</value>
        </property>
        <property name="maxInMemorySize">
            <value>4096</value>
        </property>
    </bean>

    <mvc:resources location="/WEB-INF/js/" mapping="/js/**"/>
    <mvc:resources location="/WEB-INF/css/" mapping="/css/**"/>

<!- messageConverter 不能设置在外面,要在mvc命令空间标签内进行设置即可->
    <!--    <bean  class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">-->
    <!--        <property name="messageConverters">-->
    <!--            <list>-->
    <!--                <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>-->
    <!--                <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">-->
    <!--                    <property name="supportedMediaTypes">-->
    <!--                        <list>-->
    <!--                            <value>application/json;charset=UTF-8</value>-->
    <!--                            <value>text/json;charset=UTF-8</value>-->
    <!--                            <value>text/html;charset=UTF-8</value>-->
    <!--                        </list>-->
    <!--                    </property>-->
    <!--                </bean>-->
    <!--                <bean class="org.springframework.http.converter.StringHttpMessageConverter">-->
    <!--                    <property name="supportedMediaTypes">-->
    <!--                        <list>-->
    <!--                            <value>text/plain;charset=UTF-8</value>-->
    <!--                        </list>-->
    <!--                    </property>-->
    <!--                </bean>-->
    <!--            </list>-->
    <!--        </property>-->
    <!--    </bean>-->
</beans>

文件上传Controller

@Controller
@PropertySource("classpath:script.properties")
@Slf4j
public class CtRunController {

    /**
     * default ${homeDir}/upload
     */
    private String uploadDir;
    /**
     * default ${homeDir}/ct_run.sh
     */
    private String ctRunFile;

    @Autowired
    Environment env;

    @PostConstruct
    public void init() {
        uploadDir = Paths.get(env.getProperty("homeDir"), env.getProperty("uploadDir")).toString();
        ctRunFile = Paths.get(env.getProperty("homeDir"), env.getProperty("ctRunFile")).toString();
        File file = new File(uploadDir);
        if (!file.exists()) {
            try {
                if (file.createNewFile()) {
                    log.info("文件创建成功:{}", file.getName());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static final String JPG = "jpg";
    private static final String JPEG = "jpeg";
    private static final String PNG = "png";
    private static final String SUFFIX = "-result.";

    @ResponseBody
    @RequestMapping(value = "/ct", method = RequestMethod.POST)
    public Result imageUpload(@RequestParam("file") MultipartFile file) {
        String sourceName = StringUtils.cleanPath(file.getOriginalFilename());
        if (!sourceName.endsWith(JPG) && !sourceName.endsWith(JPEG) && !sourceName.endsWith(PNG)) {
            return Result.fail("请上传正确的图片文件格式");
        }
        Path filePath = Paths.get(uploadDir, sourceName);
        store(file, filePath);
        String copyName = sourceName.replaceAll("\\.", SUFFIX);
        new Thread(() -> realCtRun(sourceName, copyName)).start();
        return Result.succeed("/alsprj/ct/" + copyName);
    }

    /**
     * 这种方式就是经过一个 ResourceHttpMessageConverter 来帮助我们实现了
     * 进一步设置body 和 请求头的工作 。HttpEntityMethodProcessor
     *
     * @param filename 文件名
     * @return 资源
     */
    @RequestMapping(value = "ct/{filename:.+}", method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity<?> serveFile(@PathVariable String filename, HttpServletResponse response) throws MalformedURLException {
        Path path = Paths.get(uploadDir, filename);
        if (!path.toFile().exists()) {
            response.setStatus(HttpStatus.MOVED_PERMANENTLY.value());
            return null;
        }
        UrlResource urlResource = new UrlResource(path.toUri());
        return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION,
                "attachment; filename=\"" + path.getFileName() + "\"").body(urlResource);
    }

    /**
     * 这种方法就是不经过框架,直接自己设置 outputStream, 和请求头
     *
     * @param filename 文件名
     * @param response 全局的一个响应
     */
    public void imageDownload(@PathVariable String filename, HttpServletResponse response) {
        File file = Paths.get(uploadDir, filename).toFile();
        if (!file.exists()) {
            response.setStatus(HttpStatus.MOVED_PERMANENTLY.value());
            return;
        }
        try (InputStream inputStream = new FileInputStream(file)) {
            OutputStream outputStream = response.getOutputStream();
            String fileName = URLEncoder.encode(file.getName(), "UTF-8");
            response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"");
            response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.IMAGE_JPEG_VALUE);
            response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(file.length()));
            Streams.copy(inputStream, outputStream, true);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                Files.delete(file.toPath());
                Files.delete(Paths.get(uploadDir, filename.replaceAll(SUFFIX, ".")));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void realCtRun(String sourceName, String copyName) {
        Path path = Paths.get(uploadDir, sourceName);
        try {
            GeneralExecutor executor = DefaultExecutorFactory.getExecutor(GeneralExecutor.class);
            String result = executor.execute(ctRunFile, path.toString());
            log.info("cmd[{} {}] result[{}]", ctRunFile, path.toString(), result);
            mockCtRun(sourceName, copyName);
        } catch (ExecuteException | ExecutorNotFoundExecption e) {
            e.printStackTrace();
        }
    }

    private void mockCtRun(String sourceName, String copyName) {
        try {
            Thread.sleep(5000);
            Files.copy(Paths.get(uploadDir, sourceName), Paths.get(uploadDir, copyName), StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    private Resource loadAsResource(Path file) {
        try {
            Resource resource = new UrlResource(file.toUri());
            if (resource.exists() || resource.isReadable()) {
                return resource;
            } else {
                throw new RuntimeException(
                        "Could not read file: " + file.getFileName());
            }
        } catch (MalformedURLException e) {
            throw new RuntimeException("Could not read file: " + file.getFileName(), e);
        }
    }

    private void store(MultipartFile file, Path save) {
        String filename = StringUtils.cleanPath(file.getOriginalFilename());
        try {
            if (file.isEmpty()) {
                throw new RuntimeException("Failed to store empty file " + filename);
            }
            if (filename.contains("..")) {
                throw new RuntimeException(
                        "Cannot store file with relative path outside current directory "
                                + filename);
            }
            try (InputStream inputStream = file.getInputStream()) {
                Files.copy(inputStream, save,
                        StandardCopyOption.REPLACE_EXISTING);
            }
        } catch (IOException e) {
            throw new RuntimeException("Failed to store file " + filename, e);
        }
    }
}

从messageConverter到大佬

org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite
在处理controller中方法的返回结果时,会从HandlerMethodReturnValueHandlerComposite的
returnValueHandlers中选出一个handler进行处理,如果是传输文件用的是ResponseEntitiy 则对应选出HttpEntitiyMethodProcessor进行处理
在这里插入图片描述
HttpEntityMethodProcessor 和 RequestResponseBodyMethodProcessor都是AbstractMessageConverterMethodProcessor具体实现类,最终会在这儿选择一个合适的。
在这里插入图片描述
MessageConverter进行内容进一步转换。具体得转换内容即是设置serveletResponse的响应体和响应头,然后正常走完 dipathcerServelet的函数栈,接着统一处理产生的异常,再从Filter栈返回,最终由Tomcat的将response由TCP协议发往客户端。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值