【问题标题】:How to resolve view in thymleaf + Springboot?如何解决百里香 + Spring Boot 中的视图?
【发布时间】:2018-07-02 14:56:24
【问题描述】:

目前,我有一个功能,就是将数据从 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();
    }
}

【问题讨论】:

    标签: spring-mvc spring-boot thymeleaf


    【解决方案1】:

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

    另一个问题是浏览器(至少是我的 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 提供的视图中。


    详情:

    csvViewResolver bean 将被 Spring Boot 的 ContentNegotiatingViewResolver 以及 BeanNameViewResolverThymeleafViewResolverViewResolverCompositeInternalResourceViewResolver 等其他 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;
    }
    

    【讨论】:

      猜你喜欢
      • 2020-05-17
      • 2019-10-10
      • 2020-11-28
      • 1970-01-01
      • 2018-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多