Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save NeilAlishev/2f7a876867a0a8516908f96ea14521e9 to your computer and use it in GitHub Desktop.
Save NeilAlishev/2f7a876867a0a8516908f96ea14521e9 to your computer and use it in GitHub Desktop.
HiddenHttpMethodFilter Java-based configuration
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
@Override
public void onStartup(ServletContext aServletContext) throws ServletException {
super.onStartup(aServletContext);
registerHiddenFieldFilter(aServletContext);
}
private void registerHiddenFieldFilter(ServletContext aContext) {
aContext.addFilter("hiddenHttpMethodFilter",
new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null ,true, "/*");
}
}
@Sysreqx
Copy link

Sysreqx commented Jun 29, 2022

Spring - Полный курс..(24 CRUD. Приложение. PATCH...)
Сейчас PATCH(update) работает без переопределения onStartup() метода?

@DenisMuzyka
Copy link

Сейчас с методами фильтра ошибка PATCH запроса не исчезает

@KarinaNovi
Copy link

@DenisMuzyka, сейчас по дефолту отключили поддержку фильтра на скрытые методы, можно включить, добавив в файлик application.properties (настроить SpringConfig на @propertysource("classpath:application.properties") - если файла не было):
spring.mvc.hiddenmethod.filter.enabled=true - включение этого фильтра

@yeoverkh
Copy link

yeoverkh commented Oct 13, 2022

@KarinaNovi

@DenisMuzyka, сейчас по дефолту отключили поддержку фильтра на скрытые методы, можно включить, добавив в файлик application.properties (настроить SpringConfig на @propertysource("classpath:application.properties") - если файла не было): spring.mvc.hiddenmethod.filter.enabled=true - включение этого фильтра

что-то не выходит настроить, перепробовал разные методы решения этой проблемы, но и этот не работает, может есть какие-то ещё возможные решения?

@engitpank
Copy link

@KarinaNovi

@DenisMuzyka, сейчас по дефолту отключили поддержку фильтра на скрытые методы, можно включить, добавив в файлик application.properties (настроить SpringConfig на @propertysource("classpath:application.properties") - если файла не было): spring.mvc.hiddenmethod.filter.enabled=true - включение этого фильтра

что-то не выходит настроить, перепробовал разные методы решения этой проблемы, но и этот не работает, может есть какие-то ещё возможные решения?

В Maven выполни clean, а затем перезапусти сервер. Мне помогло

@Fongooglish
Copy link

В таком виде как на уроке, PATCH и DELETE уже не работают.
Попробовал добавить spring.mvc.hiddenmethod.filter.enabled=true через @propertysource("classpath:application.properties") - безрезультатно... clean тоже не помогает... вообще не понятно что делать.

Copy link

ghost commented Mar 8, 2023

В таком виде как на уроке, PATCH и DELETE уже не работают.
Попробовал добавить spring.mvc.hiddenmethod.filter.enabled=true через @propertysource("classpath:application.properties") - безрезультатно... clean тоже не помогает... вообще не понятно что делать.

Мне помогла замена аннотации в контроллере
Вместо @PatchMapping("/{id}") сделал @PostMapping("/{id}")
Работает даже без фильтра
Но когда скопипастил этот фильтр, то аннотация @PatchMapping("/{id}") стала работать и ошибка 405 пропала

@AndreyNachevny
Copy link

Скопировал фильтр, сделал clean в maven и перезапустил сервер, все заработало

@hazartilirot
Copy link

hazartilirot commented Mar 15, 2023

Почитал людей, не понимаю в чём проблема. Работает с пол оборота. Передеплоил, и всё ок.)

С другой стороны, я очень намучился в начале с проектом, потому что с пятым спрингом проект никак не хотел заводиться. Создал проект с ноля, добавил Dependencies обновлённые и только после это уже пошло. IntelliJ IDEA 2022.3.3 Ultimate + TomCat 10.1.7. Может кому-то пригодится. Да, из особенностей, я прикрутил себе ломбок) Очень удобно.

 <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>19</maven.compiler.source>
        <maven.compiler.target>19</maven.compiler.target>

        <spring.version>6.0.6</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring6</artifactId>
            <version>3.1.1.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>jakarta.servlet</groupId>
            <artifactId>jakarta.servlet-api</artifactId>
            <version>6.0.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.26</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>

@hazartilirot
Copy link

hazartilirot commented Mar 16, 2023

Пока не удалил, может кому-то пригодиться

В PersonDao

private static int PEOPLE_COUNT;
    private final List<Person> people;

    {
        people = new ArrayList<Person>(
            Arrays.asList(
                new Person(++PEOPLE_COUNT, "Tom", "Jerry", "tom_jerry@example.com"),
                new Person(++PEOPLE_COUNT, "Bob", "Marly", "bob_marley@example.com"),
                new Person(++PEOPLE_COUNT, "Michael", "Jackson", "michael_jackson@example.com"),
                new Person(++PEOPLE_COUNT, "Katy", "Perry", "katy_perry@example.com")
            )
        );
    }

ещё, я слегка по-другому решил апдейт объекта

public OptionalInt findById(int id) {
        return IntStream.range(0, people.size())
                        .filter(i -> id == people.get(i).getId())
                        .findFirst();
    }

не знаю, правильно или нет, вроде работает. Я не великий знаток фанкшенал программинг в Джава, пришёл сам из Джаваскрипт

public void update(int id, Person updatedPerson) {
        var index = findById(id).orElse(-1);
        if (index < 0) {
            throw new RuntimeException("Out of boundaries");
        }
        people.set(index, updatedPerson);
    }

и сразу поделюсь SQL

CREATE TABLE person (
    id BIGSERIAL PRIMARY KEY,
    firstname VARCHAR(64),
    lastname VARCHAR(64),
    email VARCHAR(64)
);
INSERT INTO person(firstname, lastname, email) VALUES
('Tom', 'Jerry', 'tom_jerry@example.com'),
('Bob', 'Marly', 'bob_marley@example.com'),
('Michael', 'Jackson', 'michael_jackson@example.com'),
('Katy', 'Perry', 'katy_perry@example.com');

ну и для докера compose.yml

version: '3.9'

services:
  db:
    image: postgres:15.2-alpine
    restart: always
    environment:
      POSTGRES_PASSWORD: root
    ports:
      - 5432:5432

docker-compose compose.yml up -d

docker exec -it CONTAINER_ID psql -U postgres

если я не ошибаюсь, пальцы делают машинально)

@Dlakares
Copy link

Dlakares commented Mar 18, 2023

Кому не помогают решения выше, могу предложить свой вариант:
В DispactherServlet вставьте следующий код:

@OverRide
protected Filter[] getServletFilters() {
return new Filter[] {
new HiddenHttpMethodFilter(), new CharacterEncodingFilter() };
}

Лично для меня сработало, методы которые выше удалил, добавил только application.propetries с "spring.mvc.hiddenmethod.filter.enabled=true

@hazartilirot
Copy link

<properties>
       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
       <maven.compiler.source>19</maven.compiler.source>
       <maven.compiler.target>19</maven.compiler.target>

       <spring.version>6.0.6</spring.version>
   </properties>

Человек написал сверху, пересмотрел ту часть pom.xml файлы, которую я запостил раннее, в общем, ребята, там нужно указать версию вашей джавы, в моём случае, у меня установлена уже 19 версия.

@hazartilirot
Copy link

6. Отношение Один ко Многим (One-to-Many) в Hibernate

Очень долго не мог отловить багу, т.к. использовал Ломбок. В общем, в чём заключалась проблема. Когда нужно было вывести человека в консоль, то выпадала постоянно ошибка, тоже самое с вещами. Я никак не мог понять из-за чего происходит проблема, потому что трейс стек был большим и непонятным. Код, за исключением ломбка, казался, такой же как и у автора. И потом, я решил добавить перегруженный метод toString где исключил из него вещи (то есть, OneToMany связь) - и вуалля! Всё заработало) И тогда я вспомнил и понял, что из-за двусторонней связи происходит циклический вызов, один ссылается на другой, а тот в свою очередь обратно ссылается на того, и по кругу.)

Так вот, чтобы разорвать это, нужно просто над полем поставить @ToString.Exclude как в одном классе так и в другом.)

@hazartilirot
Copy link

Не мог никак завестить без @EnableTransactionManagement. Делаю всё на 6 версии.

package ru.alishev.spring.dao;


import lombok.AllArgsConstructor;
import lombok.Data;
import org.hibernate.SessionFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;
import ru.alishev.spring.models.Person;

import java.util.List;
import java.util.Optional;
@Data
@Component
@AllArgsConstructor
@EnableTransactionManagement
public class PersonDao {

    private final SessionFactory sessionFactory;

    // we don't need to open session with beginTransaction() since we use @Transactional annotation
    @Transactional(readOnly = true)
    public List<Person> index() {
        var session = sessionFactory.getCurrentSession();
        return session.createQuery("select p from Person p", Person.class).getResultList();
    }

    public Optional<Person> findByEmail(String email) {
        return null;
    }

    public Person show(int id) {
        return null;
    }

    public void save(Person person) {

    }

    public void update(int id, Person updatedPerson) {

    }

    public void delete(int id) {

    }

}

Person.java

package ru.alishev.spring.models;

import jakarta.persistence.*;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;


@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
@Table(name = "person")
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @Column(name = "firstname")
    @NotEmpty(message = "The field is required")
    @Size(min = 2, max = 30, message = "The range of 2-30 characters required")
    private String firstname;

    @Column(name = "lastname")
    @NotEmpty(message = "The field is required")
    @Size(min = 2, max = 30, message = "The range of 2-30 characters required")
    private String lastname;

    @Column(name = "email")
    @Email(message = "Email is invalid")
    @NotEmpty(message = "The field is required")
    private String email;

}

если кому-то нужен pom.xml, джава 19 версии

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>spring-controller</groupId>
    <artifactId>lesson</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>spring</name>
    <url>http://maven.apache.org</url>


    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>19</maven.compiler.source>
        <maven.compiler.target>19</maven.compiler.target>

        <spring.version>6.0.6</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring6</artifactId>
            <version>3.1.1.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>jakarta.servlet</groupId>
            <artifactId>jakarta.servlet-api</artifactId>
            <version>6.0.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.26</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>8.0.0.Final</version>
        </dependency>

        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>42.5.4</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate.orm</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>6.1.7.Final</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>6.0.6</version>
        </dependency>


    </dependencies>


    <build>
        <finalName>spring</finalName>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
            <plugins>
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>3.2.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>19</source>
                    <target>19</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

@hazartilirot
Copy link

Дошёл до Дата и время в Hibernate, не понимаю, зачем было хард-кодить дату?

<label for="birth">Date of birth: </label>
        <input type="date" data-th-field="*{dateOfBirth}" id="birth"/>
        <div class="error" data-th-if="${#fields.hasErrors('dateOfBirth')}" data-th-errors="*{dateOfBirth}">placeholder for an error</div>
        <br>

паттерн развернуть в обратную сторону, иначе выбросит в ошибку.

    @Column(name = "date_of_birth", nullable = false)
    @Temporal(TemporalType.DATE)
    @DateTimeFormat(pattern = "yyyy-mm-dd")
    private Date dateOfBirth;

сама же форма будет в нормальном виде.
Screenshot 2023-03-20 at 20 08 56

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment