Занятие №7
Spring Boot
Кернер
Денис
Приложение - "Шутки", которое может
Появление микросервисов потребовало ускорить создание проектов на Spring
Так появился Spring Boot 1.0 в апреле 2014
public interface JokeRetriever {
String getJoke();
}
@Service
public class RestJokeRetriever implements
JokeRetriever {
private final RestTemplate restTemplate;
public RestJokeRetriever(RestTemplate restTemplate)
{ this.restTemplate = restTemplate; }
@Override
public String getJoke() {
String url = "http://api.icndb.com/jokes/random";
ResponseEntity<String> response =
restTemplate.getForEntity(url, String.class);
return response.getBody();
}
}
@SpringBootApplication
@Configuration
public class JokesApplication {
// ...
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = JokesApplication.class)
public class RestJokeRetrieverTest {
@Autowired
JokeRetriever jokeRetriever;
@Test
public void joke() {
String jokeText = jokeRetriever.getJoke()
.value.getJoke();
Assert.assertFalse(jokeText.isEmpty());
Assert.assertTrue(jokeText.contains(
"Chuck Norris"));
}
}
Давайте общаться с пользователем через интерфейс командной строки.
Проект Spring Shell - позволяет вам уйти от обработки ввода и работать только с командами.
dependencies {
// ...
implementation
'org.springframework.shell:spring-shell-starter:2.0.0.RELEASE'
// ...
}
@ShellComponent
public class ShellCommands {
private final JokeRetriever jokeService;
private String lastJoke;
@ShellMethod("Get joke about Chuck Norris.")
public String joke() {
lastJoke = jokeService.getJoke().value.getJoke();
return lastJoke;
}
}
shell:>joke
Chuck Norris hosting is 101% uptime guaranteed.
shell:>joke
Product Owners never ask Chuck Norris for more features.
They ask for mercy.
Тест не запускается. Из-за Shell. Как исправить?
@RunWith(SpringRunner.class)
@SpringBootTest(
classes = JokesApplication.class,
properties = {
InteractiveShellApplicationRunner
.SPRING_SHELL_INTERACTIVE_ENABLED + "=false",
ScriptShellApplicationRunner
.SPRING_SHELL_SCRIPT_ENABLED + "=false"
}
)
public class RestJokeRetrieverTest {
А как хранить?
Как посмотреть все?
Добавим интерфейс JokeDataService.
Как реализовать?
Все остальное сделает Spring Boot
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
@Configuration
@ConditionalOnClass(ObjectMapper.class)
public class JacksonAutoConfiguration {
@Bean
public JsonComponentModule jsonComponentModule() {
return new JsonComponentModule();
}
java -jar jokes.jar --debug
============================
CONDITIONS EVALUATION REPORT
============================
Positive matches:
-----------------
CodecsAutoConfiguration.JacksonCodecConfiguration matched:
- @ConditionalOnClass found required class
'com.fasterxml.jackson.databind.ObjectMapper' (OnClassCondition)
@Override
public void save(String jokeText) {
jdbcTemplate.update(
"insert into jokes (joke) values (?)"
, jokeText);
}
@Override
public List<String> getAll() {
return jdbcTemplate.query(
"select joke from jokes",
(rs, rowNum) -> rs.getString("joke"));
}
jdbcTemplate может создать таблицу.
Как нам запустить код создания таблицы до старта приложения?
@PostConstruct
public void onPostConstruct() {
jdbcTemplate.update(
"create table jokes (joke text);");
}
Реализуем хранение
Добавляем команды в spring shell
Проверяем, что работает просмотр команд
Данные стираются при перезапуске
Как сохранить?
# путь к файлу
spring.datasource.url=jdbc:h2:file:./data/jokes
spring.datasource.driverClassName=org.h2.Driver
# логин
spring.datasource.username=sa
# пароль
spring.datasource.password=
# веб консоль
spring.h2.console.enabled=true
Нужно в классе с логированием объявить логгер
Нужно добавить настройки в приложении
logging.level.root=WARN
logging.level.io.github.bael.jokes=DEBUG
logging.file=jokes.log
private final Logger logger =
LoggerFactory.getLogger(RestJokeRetriever.class);
Пишем в лог!
logger.debug("Result: {}", response.getBody());
Как сделать лучше?
Конкретные заголовки мы скинем в чат
// используйте метод exchange RestTemplate.
// на входу ему нужна RequestEntity, которую можно создать
// указав в конструкторе HTTP заголовки, HTTP метод и URI
// Заголовки создайте так:
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add(HEADER_NAME, HEADER_VALUE);
// URI
String url = "http://example.com";
URI.create(url);
@ShellMethod("Get joke about Chuck Norris.")
public String joke(
@ShellOption(defaultValue = "NERDY")
String category) {
lastJoke = jokeService.getJoke(category).value.getJoke();
return lastJoke;
}