Рубрики
Без рубрики

Первый раунд улучшений приложения Reddit

Приложение reddit в этом тематическом исследовании появляется и постепенно начинает использоваться.

Автор оригинала: baeldung.

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

И быстрая модификация домашней страницы:

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 :




Check if already submitted



И вот наш метод контроллера:

@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. Заключение

В этой четвертой части нашего тематического исследования основное внимание было уделено небольшим, но важным улучшениям. Если вы следили за этим, вы можете увидеть, как это становится интересным и полезным маленьким приложением.