Thymeleaf 405请求方法'POST'不受支持

问题描述 投票:0回答:2

因此,我正在构建一个基本的社交媒体应用程序来学习lombok和thymeleaf,当我尝试删除mongoDB中的记录时,我遇到了问题。我的应用程序可以正常上传图像,但按下删除键将发送POST请求而不是DELETE请求。

的index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>Spring-a-Gram</title>
    <link rel="stylesheet" href="/main.css" />
</head>
<body>

<h1>Spring Boot - Social</h1>

<div>
    <table>
        <thead>
        <tr>
            <th>Id</th><th>Name</th><th>Image</th><th></th>
        </tr>
        </thead>
        <tbody>
        <tr th:each="image : ${images}">
            <td th:text="${image.id}" />
            <td th:text="${image.name}" />
            <td>
                <a th:href="@{'/images/' + ${image.name} + '/raw'}">
                    <img th:src="@{'/images/'+${image.name}+'/raw'}"
                         class="thumbnail" />
                </a>
            </td>
            <td>
                <form th:method="delete"
                      th:action="@{'/images/' + ${image.name}}">
                    <input type="submit" value="Delete" />
                </form>
            </td>
        </tr>
        </tbody>
    </table>

    <form method="post" enctype="multipart/form-data"
          action="/images">
        <p><input type="file" name="file" /></p>
        <p><input type="submit" value="Upload" /></p>
    </form>
</div>

</body>
</html>

home controller.Java

package com.alexander.springsocial;

import org.springframework.core.io.InputStreamResource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.IOException;

/**
 * @author Alexander Hartson
 */
@Controller
public class HomeController {

    private static final String BASE_PATH = "/images";
    private static final String FILENAME = "{filename:.+}";

    private final ImageService imageService;

    public HomeController(ImageService imageService) {
        this.imageService = imageService;
    }

    @GetMapping("/")
    public Mono<String> index(Model model) {
        model.addAttribute("images", imageService.findAllImages());
        return Mono.just("index");
    }

    @GetMapping(value = BASE_PATH + "/" + FILENAME + "/raw",
        produces = MediaType.IMAGE_JPEG_VALUE)
    @ResponseBody
    public Mono<ResponseEntity<?>> oneRawImage(
            @PathVariable String filename) {
        return imageService.findOneImage(filename).map(resource -> {
            try {
                return ResponseEntity.ok()
                        .contentLength(resource.contentLength())
                        .body(new InputStreamResource(
                                resource.getInputStream()));
            } catch (IOException e) {
                return ResponseEntity.badRequest()
                        .body("Couldn't find " + filename +
                                " => " + e.getMessage());
            }
        });
    }

    @PostMapping(value = BASE_PATH)
    public Mono<String> createFile(@RequestPart(name = "file")
                                   Flux<FilePart> files) {
        return imageService.createImage(files)
                .then(Mono.just("redirect:/"));
    }

    @DeleteMapping(BASE_PATH + "/" + FILENAME)
    public Mono<String> deleteFile(@PathVariable String filename) {
        return imageService.deleteImage(filename)
                .then(Mono.just("redirect:/"));
    }
}

image service.Java

package com.alexander.springsocial;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.UUID;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.FileSystemUtils;

/**
 * @author Alexander Hartson
 */
@Service
public class ImageService {

    public static String UPLOAD_ROOT = "upload-dir";

    // tag::injection[]
    private final ResourceLoader resourceLoader;

    private final ImageRepository imageRepository;

    public ImageService(ResourceLoader resourceLoader,
                        ImageRepository imageRepository) {
        this.resourceLoader = resourceLoader;
        this.imageRepository = imageRepository;
    }
    // end::injection[]

    // tag::1[]
    public Flux<Image> findAllImages() {
        return imageRepository.findAll()
                .log("findAll");
    }
    // end::1[]

    public Mono<Resource> findOneImage(String filename) {
        return Mono.fromSupplier(() ->
                resourceLoader.getResource(
                        "file:" + UPLOAD_ROOT + "/" + filename))
                .log("findOneImage");
    }

    // tag::2[]
    public Mono<Void> createImage(Flux<FilePart> files) {
        return files
                .log("createImage-files")
                .flatMap(file -> {
                    Mono<Image> saveDatabaseImage = imageRepository.save(
                            new Image(
                                    UUID.randomUUID().toString(),
                                    file.filename()))
                            .log("createImage-save");

                    Mono<Void> copyFile = Mono.just(
                            Paths.get(UPLOAD_ROOT, file.filename())
                                    .toFile())
                            .log("createImage-picktarget")
                            .map(destFile -> {
                                try {
                                    destFile.createNewFile();
                                    return destFile;
                                } catch (IOException e) {
                                    throw new RuntimeException(e);
                                }
                            })
                            .log("createImage-newfile")
                            .flatMap(file::transferTo)
                            .log("createImage-copy");

                    return Mono.when(saveDatabaseImage, copyFile)
                            .log("createImage-when");
                })
                .log("createImage-flatMap")
                .then()
                .log("createImage-done");
    }
    // end::2[]

    // tag::3[]
    public Mono<Void> deleteImage(String filename) {
        Mono<Void> deleteDatabaseImage = imageRepository
                .findByName(filename)
                .log("deleteImage-find")
                .flatMap(imageRepository::delete)
                .log("deleteImage-record");

        Mono<Object> deleteFile = Mono.fromRunnable(() -> {
            try {
                Files.deleteIfExists(
                        Paths.get(UPLOAD_ROOT, filename));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        })
                .log("deleteImage-file");

        return Mono.when(deleteDatabaseImage, deleteFile)
                .log("deleteImage-when")
                .then()
                .log("deleteImage-done");
    }
    // end::3[]

    /**
     * Pre-load some test images
     *
     * @return Spring Boot {@link CommandLineRunner} automatically
     *         run after app context is loaded.
     */
    @Bean
    CommandLineRunner setUp() throws IOException {
        return (args) -> {
            FileSystemUtils.deleteRecursively(new File(UPLOAD_ROOT));

            Files.createDirectory(Paths.get(UPLOAD_ROOT));

            FileCopyUtils.copy("Test file",
                    new FileWriter(UPLOAD_ROOT +
                            "/image1.jpg"));

            FileCopyUtils.copy("Test file2",
                    new FileWriter(UPLOAD_ROOT +
                            "/image2.jpg"));

            FileCopyUtils.copy("Test file3",
                    new FileWriter(UPLOAD_ROOT + "/image3.jpg"));
        };
    }
}

摇篮

buildscript {
    ext {
        springBootVersion = '2.0.4.RELEASE'
    }
    repositories {
        mavenCentral()
        maven { url "https://repo.spring.io/snapshot" }
        maven { url "https://repo.spring.io/milestone" }
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group = 'com.alexander.spring-social'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
    maven { url "https://repo.spring.io/snapshot" }
    maven { url "https://repo.spring.io/milestone" }
    maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
}


dependencies {
    // tag::netty
    compile('org.springframework.boot:spring-boot-starter-webflux') {
        exclude group: 'org.springframework.boot',
        module: 'spring-boot-starter-reactor-netty'
    }
    compile('org.springframework.boot:spring-boot-starter-tomcat')
    compile('org.springframework.boot:spring-boot-starter-thymeleaf')
    compile('org.springframework.boot:spring-boot-starter-data-mongodb-reactive')
    compile('org.synchronoss.cloud:nio-multipart-parser')
    // Specify lombok version
    compileOnly('org.projectlombok:lombok:1.18.2')
    testCompile('org.springframework.boot:spring-boot-starter-test')
    testCompile("io.projectreactor:reactor-test")
}

enter image description here

从我在此屏幕截图中的调试开始,即使我指定了“删除”,看起来表单方法将操作定义为“帖子”?对我来说,为什么这样做是没有意义的。任何想法,将不胜感激。

spring mongodb spring-boot thymeleaf
2个回答
1
投票

我认为你误解了HTTP和HTML。 DELETEPUT都是HTTP协议的一部分。

直到HTML 5 DELETEPUT不受支持,并且它仍然非常有限,具体取决于每个浏览器。我怀疑是百里香叶不支持DELETE作为一种形式方法,导致它改变为POST方法。

我建议将你的方法改为POST并让你的控制器听POST请求。

侦听HTTP qazxsw poi请求的控制器对于例如非常有用。 RESTful服务。


0
投票

我今天早上设法解决了这个问题。我将HomeController上的@DeleteMapping更改为@PostMapping。我不是100%肯定为什么它解决了这个问题我只知道它有效。

再次感谢!

© www.soinside.com 2019 - 2024. All rights reserved.