Spring не распознает JSP шаблон
При попытке перейти по пути, указанному в контроллере - выдаётся 404 ошибка.
В качестве имени отображения возвращается 'admin'.
Я создал admin.jsp, но он игнорируется.
При этом если создать шаблон admin.html - все работает нормально.
Но мне это не подходит. Нужен именно JSP!
Вот контроллер:
@GetMapping("/admin")
public String userList(Model model) {
model.addAttribute("allUsers", userService.allUsers());
return "admin";
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<java.version>1.8</java.version>
<mysql.connetor.version>8.0.15</mysql.connetor.version>
<jsonwebtoken.version>0.8.0</jsonwebtoken.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MySQL connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.connetor.version}</version>
</dependency>
<!-- JSON Web Token lib -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jsonwebtoken.version}</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Ответы (1 шт):
В чем проблема?
Посмотрим на приложенный pom.xml
Там мы найдем следующую зависимость:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Данная зависимость подключает шаблонизатор Thymeleaf и настраивает Spring, на работу с ним, а не с JSP.
Поэтому шаблон admin.html обрабатывался, а admin.jsp - нет.
(Thymeleaf хранит свои шаблоны в фйлах с расширением .html)
В целом я советую не пугаться и не избегать его категорически.
Лично я уже давно использую его в проектах со Spring'ом и Spring уже давно его используют в качестве шаблонизатора по умолчанию.
Поэтому причин "шарахаться" от него я не вижу.
Подробнее о Thymeleaf можно узнать на официальном сайте:
https://www.thymeleaf.org/
Не отходя от pom.xml
Взглянем еще внимательнее на зависимости:
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- ... -->
<dependencies>
<!-- ... -->
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- ... -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- ... -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- ... -->
</dependencies>
</project>
Я уже понял что Вы любите Lombok, но зачем его подключать 4 раза?
Не надо так делать.
Также у Вас дублируется зависимость javax.validation:validation-api
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- ... -->
<dependencies>
<!-- ... -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<!-- ... -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<!-- ... -->
</dependencies>
<!-- ... -->
</project>
Настоятельно советую все дубли заблаговременно убрать, иначе потом вы рискуете нарваться на конфликт версий или логическую ошибку(будете думать что удалили или поправили зависимость - а на самом деле нет)
Как настроить Spring для работы с JSP
Для начала удалим зависимость Thymeleaf с настройками.
Для этого из pom.xml удаляем следующие строки:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Далее важно понимать, что jsp - это не скрипты и они не являются исполняемыми файлами.
JSP сначала транслируется в код сервлета, а потом уже выполняется.
Делается это с помощью компилятора JSP-страниц Jasper.
Второе, что стоит понять это то,что когда Вы пользуетесь JSP, вы используете не только Java-код внутри верстки (а это и есть дефолтный функционал JSP).
Чаще всего JSP используют совместно с JSTL (JSP Standart Tag Library).
Это библиотека стандартных тегов JSP, которая упрощает создание шаблонов, вывод данных, позволяет с помощью тегов реализовывать условия, циклы и пр. функционал.
<c:if ... ></c:if> и др. оттуда.
И напоследок нужно понимать, что всего этого добра сейчас у вас нет.
Соответственно его нужно подключить.
Добавляем в pom.xml:
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
Переимпортируем заново все зависимости в Maven.
Далее нам следует настроить ViewResolver (компонент, который отвечает за определение и нахождение наших шаблонов)
Для этого достаточно создать бин, возвращающий объект имплементирующий
интерфейс ViewResolver.
@Bean
public ViewResolver getViewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
Здесь все просто:
- Cоздаем объект
- Указываем ему путь к нахождению шаблонов (в моем случае /WEB-INF/jsp/)
- Указываем ему расширение (.jsp)
- Указываем ему тип шаблона(в данном случае JstlView)
Данный бин, для простоты, можно положить прямо в Application
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
@Bean
public ViewResolver getViewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
}
При этом шаблоны у меня хранятся в {{ PROJECT_ROOT }}/src/main/WEB-INF/jsp/
src
|-main
|-java
| \ ...
|-resources
| \ ...
|-WEB-INF
|-jsp
|-admin.jsp
|-...
^
/
/
ВОТ ТУТ
В итоге все должно работать.