如何在thymleaf + Springboot中解析视图?

时间:2018-07-02 03:56:15

标签: spring-mvc spring-boot thymeleaf

当前,我具有将数据从MYSQL转换为CSV的功能。 CSV函数包含使用viewResolver的webconfig。问题是,当我使用以下功能时,页面无法查看,但可以下载CSV文件,反之亦然。我需要配置什么吗?

-配置ContentNegotiatingViewResolver

  @Bean
public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {

ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(manager);

// Define all possible view resolvers
List<ViewResolver> resolvers = new ArrayList<>();

resolvers.add(csvViewResolver());
    resolver.setViewResolvers(resolvers);
    return resolver;
}

WebConfig-完整代码

    package com.portal.dmtt.csvDownload.config;

import com.portal.dmtt.csvDownload.viewResolver.CsvViewResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;

import java.util.ArrayList;
import java.util.List;

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer
                .defaultContentType(MediaType.APPLICATION_JSON)
                .favorPathExtension(true);
    }
    /*
     * Configure ContentNegotiatingViewResolver
     */
    @Bean
    public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {
        ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
        resolver.setContentNegotiationManager(manager);

        // Define all possible view resolvers
        List<ViewResolver> resolvers = new ArrayList<>();

        resolvers.add(csvViewResolver());
        resolver.setViewResolvers(resolvers);
        return resolver;
    }

    /*
     * Configure View resolver to provide Csv output using Super Csv library to
     * generate Csv output for an object content
     */
    @Bean
    public ViewResolver csvViewResolver() {
        return new CsvViewResolver();
    }



}

导出控制器

package com.portal.dmtt.csvDownload.controller;

import com.portal.dmtt.repo.dmttDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class ExportController {

    @Autowired
    private dmttDAO dmttDAO;

    /**
     * Handle request to download an Excel document
     */
    @GetMapping("/dl")
    public String download(Model model) {

        model.addAttribute("results", dmttDAO.getAllResultSet());
        return "";
    }

}

摘要视图

package com.portal.dmtt.csvDownload.view;

 import org.springframework.web.servlet.view.AbstractView;

 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.util.Map;

 public abstract class AbstractCsvView extends AbstractView {

     private static final String CONTENT_TYPE = "text/csv";

     public AbstractCsvView() {
         setContentType(CONTENT_TYPE);
     }

     @Override
     protected boolean generatesDownloadContent() {
         return true;
     }


     @Override
     protected final void renderMergedOutputModel(
             Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
         response.setContentType(getContentType());
         buildCsvDocument(model, request, response);
     }

     protected abstract void buildCsvDocument(
             Map<String, Object> model, HttpServletRequest request, HttpServletResponse response)
             throws Exception;


 }

CSV视图

package com.portal.dmtt.csvDownload.view;

import com.portal.dmtt.model.exceptionMonitoring.FN_Result_Set;
import org.supercsv.io.CsvBeanWriter;
import org.supercsv.io.ICsvBeanWriter;
import org.supercsv.prefs.CsvPreference;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;

public class CsvView extends AbstractCsvView {


    @Override
    protected void buildCsvDocument(Map<String, Object> model, HttpServletRequest request, HttpServletResponse
            response) throws Exception {

        response.setHeader("Content-Disposition", "attachment; filename=\"my-csv-file.csv\"");

        List<FN_Result_Set> fnResultSetList = (List<FN_Result_Set>) model.get("results");

        String[] header = {"SP_ID", "SP_ID", "XFER_XMIT_STATUS", "XFER_FILE_NAME", "UPDATE_TS", "YYMM", "REMARKS"};

        try {

            ICsvBeanWriter csvWriter = new CsvBeanWriter(response.getWriter(),
                    CsvPreference.STANDARD_PREFERENCE);

            csvWriter.writeHeader(header);

            for (FN_Result_Set user : fnResultSetList) {
                csvWriter.write(user, header);
            }
            csvWriter.close();

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

查看解析器

package com.portal.dmtt.csvDownload.viewResolver;

import com.portal.dmtt.csvDownload.view.CsvView;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;

import java.util.Locale;

public class CsvViewResolver implements ViewResolver {

    @Override
    public View resolveViewName(String s, Locale locale) throws Exception {

        return new CsvView();
    }
}

1 个答案:

答案 0 :(得分:0)

问题之一是您的CSVViewResolver正在解析任何视图名称的视图。如果视图名称null不为空,则可能要从CSVViewResolver.resolveViewName()返回s

另一个问题是浏览器(至少是我的Chrome)不会发送text/csv作为Accept标头,而是发送text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8

configureContentNegotiation中为CSV明确设置媒体类型

@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    configurer
            .defaultContentType(MediaType.APPLICATION_JSON)
            .favorPathExtension(true)
            .mediaType("csv", MediaType.parseMediaType("text/csv"));
}

删除Bean contentNegotiatingViewResolver

您不应创建一个contentNegotiatingViewResolver,因为Spring Boot提供了一个。如果提供一个,则将有两个这种类型,而您将没有Thymeleaf ViewResolver。由于您的CSVViewResolver将返回任何视图名称的视图,因此该视图将在您提供的ContentNegotiatingViewResolver中解析,而不是在Spring提供的视图中解析。


详细信息:

Spring Boot的csvViewResolver将与ContentNegotiatingViewResolverBeanNameViewResolverThymeleafViewResolverViewResolverComposite等其他对象一起拾取InternalResourceViewResolver bean。

要对此进行调试,请在DispatcherServlet.resolveViewName上设置一个断点:

protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
        HttpServletRequest request) throws Exception {

    for (ViewResolver viewResolver : this.viewResolvers) {
        View view = viewResolver.resolveViewName(viewName, locale);
        if (view != null) {
            return view;
        }
    }
    return null;
}