1. Обзор
Веб – приложение Reddit Case Study продвигается хорошо-и небольшое веб-приложение формируется и постепенно становится пригодным для использования.
В этой части мы собираемся внести небольшие улучшения в существующую функциональность – некоторые внешние, некоторые нет – и в целом сделать приложение лучше .
2. Проверка настроек
Давайте начнем с некоторых простых, но полезных проверок, которые необходимо выполнить при загрузке приложения:
@Autowired
private UserRepository repo;
@PostConstruct
public void startupCheck() {
if (StringUtils.isBlank(accessTokenUri) ||
StringUtils.isBlank(userAuthorizationUri) ||
StringUtils.isBlank(clientID) || StringUtils.isBlank(clientSecret)) {
throw new RuntimeException("Incomplete reddit properties");
}
repo.findAll();
}Обратите внимание, как мы используем аннотацию @PostConstruct здесь, чтобы подключиться к жизненному циклу приложения после завершения процесса внедрения зависимостей.
Простыми целями являются:
- проверьте, есть ли у нас все свойства, необходимые для доступа к API Reddit
- убедитесь, что уровень сохраняемости работает (выполнив простой вызов find All )
Если мы потерпим неудачу – мы сделаем это раньше.
3. Проблема Reddit “Слишком много запросов”
API Reddit агрессивен в ограничении скорости запросов, которые не отправляют уникальный ” User-Agent “.
Итак – нам нужно добавить этот уникальный User-Agent заголовок в наш redditRestTemplate – используя пользовательский перехватчик :
3.1. Создание Пользовательского Перехватчика
Вот наш пользовательский перехватчик – UserAgentInterceptor :
public class UserAgentInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(
HttpRequest request, byte[] body,
ClientHttpRequestExecution execution) throws IOException {
HttpHeaders headers = request.getHeaders();
headers.add("User-Agent", "Schedule with Reddit");
return execution.execute(request, body);
}
}3.2. Настройка reddit RestTemplate
Нам, конечно, нужно настроить этот перехватчик с помощью reddit RestTemplate , который мы используем:
@Bean
public OAuth2RestTemplate redditRestTemplate(OAuth2ClientContext clientContext) {
OAuth2RestTemplate template = new OAuth2RestTemplate(reddit(), clientContext);
List list = new ArrayList();
list.add(new UserAgentInterceptor());
template.setInterceptors(list);
return template;
} 4. Настройте базу данных H2 для тестирования
Далее – давайте продолжим и настроим в памяти DB- H2 – для тестирования. Нам нужно добавить эту зависимость в ваш pom.xml :
com.h2database h2 1.4.187
И определите persistence-test.properties :
## DataSource Configuration ### jdbc.driverClassName=org.h2.Driver jdbc.url=jdbc:h2:mem:oauth_reddit;DB_CLOSE_DELAY=-1 jdbc.user=sa jdbc.pass= ## Hibernate Configuration ## hibernate.dialect=org.hibernate.dialect.H2Dialect hibernate.hbm2ddl.auto=update
5. Переключитесь на Thymeleaf
JSP вышел, а Тимелиф вошел.
5.1. Изменить pom.xml
Во-первых, нам нужно добавить эти зависимости в ваш pom.xml:
org.thymeleaf thymeleaf 2.1.4.RELEASE org.thymeleaf thymeleaf-spring4 2.1.4.RELEASE org.thymeleaf.extras thymeleaf-extras-springsecurity3 2.1.2.RELEASE
5.2. Создайте ThymeleafConfig
Далее – простой ThymeleafConfig :
@Configuration
public class ThymeleafConfig {
@Bean
public TemplateResolver templateResolver() {
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
templateResolver.setPrefix("/WEB-INF/jsp/");
templateResolver.setSuffix(".jsp");
return templateResolver;
}
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.addDialect(new SpringSecurityDialect());
return templateEngine;
}
@Bean
public ViewResolver viewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(1);
return viewResolver;
}
}И добавьте его в наш ServletInitializer :
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(PersistenceJPAConfig.class, WebConfig.class,
SecurityConfig.class, ThymeleafConfig.class);
return context;
}5.3. Изменить home.html
И быстрая модификация домашней страницы:
Schedule to Reddit
6. Выход из системы
Теперь – давайте сделаем некоторые улучшения, которые на самом деле видны конечному пользователю приложения. Начнем с выхода из системы.
Мы добавляем простую опцию выхода из системы в приложение, изменив нашу конфигурацию безопасности:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.....
.and()
.logout()
.deleteCookies("JSESSIONID")
.logoutUrl("/logout")
.logoutSuccessUrl("/");
}7. Автозаполнение Субреддита
Далее – давайте реализуем простую функцию автозаполнения для заполнения его субреддитом; писать его вручную не очень хороший способ, так как есть справедливый шанс ошибиться.
Давайте начнем с клиентской стороны:
Достаточно просто. Теперь на стороне сервера:
@RequestMapping(value = "/subredditAutoComplete")
@ResponseBody
public String subredditAutoComplete(@RequestParam("term") String term) {
MultiValueMap param = new LinkedMultiValueMap();
param.add("query", term);
JsonNode node = redditRestTemplate.postForObject(
"https://oauth.reddit.com//api/search_reddit_names", param, JsonNode.class);
return node.get("names").toString();
} 8. Проверьте, Есть ли Ссылка Уже на Reddit
Далее – давайте посмотрим, как проверить, была ли ссылка уже отправлена ранее в Reddit.
Вот наш submissionForm.html :
И вот наш метод контроллера:
@RequestMapping(value = "/checkIfAlreadySubmitted", method = RequestMethod.POST)
@ResponseBody
public String checkIfAlreadySubmitted(
@RequestParam("url") String url, @RequestParam("sr") String sr) {
JsonNode node = redditRestTemplate.getForObject(
"https://oauth.reddit.com/r/" + sr + "/search?q=url:" + url + "&restrict_sr=on", JsonNode.class);
return node.get("data").get("children").toString();
}9. Развертывание в Heroku
Наконец – мы собираемся настроить развертывание на Heroku – и использовать их бесплатный уровень для питания примера приложения.
9.1. Изменить pom.xml
Во-первых, нам нужно будет добавить этот плагин Web Runner в pom.xml :
org.apache.maven.plugins maven-dependency-plugin 2.3 package copy com.github.jsimone webapp-runner 7.0.57.2 webapp-runner.jar
Примечание – мы будем использовать Web Runner для запуска нашего приложения на Heroku.
Мы собираемся использовать Postgresql на Heroku, поэтому нам нужно будет иметь зависимость от драйвера:
org.postgresql postgresql 9.4-1201-jdbc41
9.2. Профиль
Нам нужно определить процесс, который будет выполняться на сервере в файле Procfile – следующим образом:
web: java $JAVA_OPTS -jar target/dependency/webapp-runner.jar --port $PORT target/*.war
9.3. Создайте приложение Heroku
Чтобы создать приложение Heroku из вашего проекта, мы просто:
cd path_to_your_project heroku login heroku create
9.4. Конфигурация базы данных
Далее – нам нужно настроить нашу базу данных, используя свойства базы данных нашего приложения Postgres .
Например, вот свойства persistence-prod.:
## DataSource Configuration ## jdbc.driverClassName=org.postgresql.Driver jdbc.url=jdbc:postgresql://hostname:5432/databasename jdbc.user=xxxxxxxxxxxxxx jdbc.pass=xxxxxxxxxxxxxxxxx ## Hibernate Configuration ## hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect hibernate.hbm2ddl.auto=update
Обратите внимание, что нам нужно получить сведения о базе данных [имя хоста, имя базы данных, пользователь и пароль] с панели мониторинга Heroku.
Кроме того, как и в большинстве случаев , ключевое слово “пользователь” является зарезервированным словом в Postgres , поэтому нам нужно изменить имя таблицы сущностей “ User “.:
@Entity
@Table(name = "APP_USER")
public class User { .... }9.5. Нажмите код на Heroku
Теперь – давайте отправим код в Heroku:
git add . git commit -m "init" git push heroku master
10. Заключение
В этой четвертой части нашего тематического исследования основное внимание было уделено небольшим, но важным улучшениям. Если вы следили за этим, вы можете увидеть, как это становится интересным и полезным маленьким приложением.