Создание ссылки для загрузки файла с помощью Spring Boot и Thymeleaf

Это может показаться тривиальным вопросом, но после нескольких часов поисков я так и не нашел на него ответа. Проблема, насколько я понимаю, в том, что я пытаюсь вернуть FileSystemResource от контроллера, и Thymeleaf ожидает, что я предоставлю String ресурс, с помощью которого он будет отображать следующую страницу. Но поскольку я возвращаю FileSystemResource, я получаю следующую ошибку:

org.thymeleaf.exceptions.TemplateInputException: Error resolving template "products/download", template might not exist or might not be accessible by any of the configured Template Resolvers

Я использовал отображение контроллера:

@RequestMapping(value="/products/download", method=RequestMethod.GET)
public FileSystemResource downloadFile(@Param(value="id") Long id) {
    Product product = productRepo.findOne(id);
    return new FileSystemResource(new File(product.getFileUrl()));
}

Моя HTML-ссылка выглядит примерно так:

<a th:href="${'products/download?id=' + product.id}"><span th:text="${product.name}"></span></a>

Я не хочу, чтобы меня никуда перенаправляли, мне просто нужно, чтобы файл был загружен после нажатия ссылки. Это действительно правильная реализация? Я не уверен.


person shyam    schedule 23.04.2015    source источник
comment
<a th:href="${'products/download?id=' + product.id}"><span th:text="${product.name}"></span></a> $ в начале должно быть @, вы можете попробовать так?   -  person mtyurt    schedule 23.04.2015
comment
Если я использую @, product.id не заменяется фактическим идентификатором продукта.   -  person shyam    schedule 23.04.2015
comment
Потому что это должно быть th:href="@{'products/download?id=' + ${product.id}}", как указано в документации.   -  person mtyurt    schedule 23.04.2015
comment
Ага. Но ошибка остается. Фактический идентификатор теперь отображается в запросе на получение.   -  person shyam    schedule 23.04.2015
comment
Теперь ваша проблема связана с Весной. Отметьте этот вопрос: stackoverflow.com/questions/ 5673260 /   -  person mtyurt    schedule 23.04.2015
comment
Второй ответ на этот вопрос - это именно то, что я сделал, насколько я могу судить. И, IMHO, я думаю, проблема в том, что url в адресной строке меняется при переходе по ссылке. И, что касается Thymeleaf, у него нет шаблона html, относящегося к этому URL-адресу, поэтому возникает ошибка.   -  person shyam    schedule 23.04.2015
comment
Вы включаете аннотацию @ResponseBody?   -  person Leandro Carracedo    schedule 23.04.2015
comment
@PatrickLC Это сработало! Если вы представите это как ответ, я приму его.   -  person shyam    schedule 23.04.2015


Ответы (5)


Вам нужно изменить th:href, чтобы он выглядел так:

<a th:href="@{|/products/download?id=${product.id}|}"><span th:text="${product.name}"></span></a>

Затем вам также нужно изменить свой контроллер и добавить аннотацию @ResponseBody:

@RequestMapping(value="/products/download", method=RequestMethod.GET)
@ResponseBody
public FileSystemResource downloadFile(@Param(value="id") Long id) {
    Product product = productRepo.findOne(id);
    return new FileSystemResource(new File(product.getFileUrl()));
}
person Leandro Carracedo    schedule 23.04.2015
comment
Привет. Только что я заметил, что у вас есть символ | вместо обычного '. Что я должен знать? - person shyam; 23.04.2015
comment
Это просто еще один способ объединения, но он проще, чем использование '. Отметьте этот ответ: stackoverflow.com/a/22064656/4316870 - person Leandro Carracedo; 23.04.2015
comment
Большой! Спасибо за информацию! :) - person shyam; 23.04.2015

Иметь URL-адрес href, например

<a th:href="@{|/download?id=${obj.id}|}">download</a>

Затем в контроллере определите, как показано ниже, для записи файла в объект ответа.

@RequestMapping(value="/download", method=RequestMethod.GET)
public void downloadFile(@Param(value="id") Long id,HttpServletResponse response) {
        try {
            Ticket ticket = this.findById(id);
        String fileName =  Paths.get(property.getFileLocation()).resolve(ticket.getFilePath()).toString();
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        String headerKey = "Content-Disposition";
        String headerValue = String.format("attachment; filename=\"%s\"", fileName);
        response.setHeader(headerKey, headerValue);
        FileInputStream inputStream;
        try {
            inputStream = new FileInputStream(fileName);
            try {
                int c;
                while ((c = inputStream.read()) != -1) {
                response.getWriter().write(c);
                }
            } finally {
                if (inputStream != null)
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    response.getWriter().close();
            }
        } catch (IOException e) {
            e.printStackTrace();

        }
    }
person Padmanabhan Velu    schedule 06.12.2019
comment
Это работает для меня, первый ответ бросает мне экран, полный странных персонажей ... - person Luis Manrique; 11.11.2020

Thymeleaf очень хорошо документирован, вы можете найти о буквальных заменах (что Леандро показал выше) в руководстве - раздел 4.7

Выдержка из инструкции

<span th:text="|Welcome to our application, ${user.name}!|">
person Andrei Epure is hiring    schedule 23.02.2017

для меня ответ от @ leandro-carracedo сработал, но браузер просто перечислял содержимое файла, а не загружал.

Это исправило, что:

<a download="results.csv" th:href=... </a>
person Vetras    schedule 22.08.2019

Thymeleaf <td><a th:href="${fileDetail.MsgFileName}" th:text="${fileDetail.MsgFileName}" /></td>.URL подготовлен на стороне сервера, а href создан на стороне клиента

person user1434517    schedule 30.05.2021