4. Исправить ошибки в Spring Boot приложении
Условие задачи:
Необходимо провести рефакторинг Spring Boot приложения и исправить ошибки в структуре и коде.
Нужно обратить внимание на:
расположение классов и пакетов;
component scanning Spring Boot;
корректные импорты аннотаций;
синтаксис
@GetMapping;корректную регистрацию контроллера в Spring Context.
Код:
package com.home.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
package com.home.controller;
@Controller
public class Controller {
@GetMapping("/")
public String test() {
return "test";
}
}
Спойлеры к решению
Подсказки
.java-файле не может быть нескольких объявлений package.💡
@Controller находится в org.springframework.stereotype.💡
@GetMapping находится в org.springframework.web.bind.annotation.💡 Обрати внимание, от какого пакета Spring Boot начинает поиск компонентов.
💡 Главный класс приложения лучше разместить в общем родительском пакете для остальных компонентов.
Решение
Удобная структура проекта:
com.home
├── App.java
└── controller
└── HomeController.java
App.java:
package com.home;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
HomeController.java:
package com.home.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HomeController {
@GetMapping("/")
public String test() {
return "test";
}
}
Каждый файл содержит только одно объявление:
package ...
и находится в директории, соответствующей своему пакету.
Важная проблема исходной структуры связана с расположением главного класса:
com.home.app.App
com.home.controller.Controller
@SpringBootApplication включает поиск компонентов начиная с пакета, в котором расположен класс приложения, и его подпакетов.
Если App находится в:
com.home.app
то автоматически сканируются:
com.home.app
com.home.app.*
Но пакет:
com.home.controller
является соседним, а не дочерним. Поэтому контроллер может не попасть в Spring Context.
Размещение App в общем корневом пакете:
com.home
решает эту проблему:
com.home
├── App
└── controller
└── HomeController
Теперь com.home.controller входит в область component scanning.
Также должны использоваться правильные импорты:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
Аннотация маршрута записывается как:
@GetMapping("/")
Метод:
public String test() {
return "test";
}
при использовании @Controller возвращает имя представления test. То есть Spring MVC будет искать соответствующий шаблон, например test.html, если подключён шаблонизатор.
Если задача состоит именно в том, чтобы по запросу / вернуть текст:
test
то контроллер можно сделать REST-контроллером:
package com.home.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HomeController {
@GetMapping("/")
public String test() {
return "test";
}
}
В этом случае строка "test" будет записана непосредственно в HTTP response body.
Основные исправления:
классы разделены по отдельным файлам;
главный класс перенесён в общий родительский пакет;
контроллер попадает в component scanning;
добавлены правильные импорты;
исправлен синтаксис
@GetMapping;имя
Controllerзаменено на более понятноеHomeController;уточнена разница между
@Controllerи@RestController.