Статьи

Веб-профиль Java EE 6.

Java SE в порядке.

Java EE это зло.

Это то, что я всегда думал. Ну, не больше, сейчас. Позвольте мне поделиться своим опытом.

Несколько недель назад я начал думать о переносе устаревшего приложения spring + hibernate + tomcat на новую платформу:
SAP NetWeaver Cloud . Я знаю, о чем вы думаете, придурки: этот пост ухудшается. Он начинается с Java EE, не совсем вызывающий, и теперь входит в SAP , а не просто вундеркинд… Пожалуйста, дайте мне еще десять минут!

Конфигурация весеннего слоя моего старого приложения была основана на xml (она была написана до появления аннотаций в игре). Я боялся перспективы погрузиться в — мой собственный — ужас XML снова.

Затем появился этот твит:

и через несколько дней эта документация . И я попробовал это. И это сработало. И я передумал о Java EE. В блоге Билла Водопроводчика есть пост, который точно описывает мои мысли после этого опыта.

Так много с бла бла бла. Давайте начнем кодировать! Если вы спешите, клонируйте полное приложение по адресу https://github.com/cthiebaud/adventscloud.

Перед тем как вырезать и вставить как сумасшедший, давайте кратко опишем, о чем код ниже Мы создадим и развернем в облаке (бесплатно) крошечное веб-приложение, которое:

1. входит в систему пользователя (извините, вам понадобится учетная запись SAP Community Network , не волнуйтесь, это бесплатно),

2. при входе в систему скажите «привет» остальному миру от имени пользователя,

3. при последующих входах в систему вместо того, чтобы снова и снова говорить «привет», просто сохраните в базе данных, сколько было сказано «привет», и

4. вот и все.

Для этого нам понадобится один интерфейс Java, три класса Java, одна страница сервера Java, а также последний штрих в файлах persistence.xml (для конфигурации базы данных) и web.xml (для мастера ограничения безопасности).

Для краткости, пакеты, импорт, получатели и установщики опущены в коде ниже. Но, как только что сказано, полный исходный код доступен @ github

Напишите один Hello.java POJO (полный класс здесь ):

1
2
3
4
5
6
7
8
public class Hello {
 
  private Long      id;
  private String    username;
  private Integer   counter;
  private Timestamp when;
  // ... getters and setters ...
}

Совершенно очевидно: для каждого username этот POJO будет хранить в counter сколько раз пользователь нажимал index.jsp нашего приложения и when было в последний раз.

Аннотируйте это Hello.java POJO с аннотациями JPA (полный класс здесь ):

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Entity
@Table(name="T_HELLO")
@NamedQueries( {
  @NamedQuery(name = "allHellos", query = "select h from Hello h"),
  @NamedQuery(name = "helloFromUsername", query = "select h from Hello h where h.username = :username")
})
public class Hello {
 
  @Id
  @GeneratedValue
  private Long      id;
  @Column(name="A_USER", unique=true, nullable=false)
  private String    username;
  @Column(name="A_COUNTER", nullable=false)
  private Integer   counter;
  @Version
  @Column(name="A_TIMESTAMP", nullable=false)
  private Timestamp when;
 
  public Hello() {
    this.counter = 1;
  }
  // ... getters and setters ...
}

Напишите один интерфейс HelloDao.java, который обращается к POJO (полный интерфейс здесь )

1
2
3
4
5
6
7
@Local
public interface HelloDao {
 
  List<hello> getAll();
  Hello fromUsername(String username);
  Hello save(Hello hello);
}

Напишите один HelloBean.java, аннотированный аннотациями EJB, который реализует интерфейс HelloDao (полный класс здесь ):

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@Stateless
public class HelloBean implements HelloDao {
 
  @PersistenceContext
  private EntityManager em;
 
  @Override
  public List<hello> getAll() {
    @SuppressWarnings("unchecked")
    List<hello> hellos = (List<hello>)em.createNamedQuery("allHellos").getResultList();
 
    Collections.sort(hellos, new Comparator<hello>() {
      @Override
      public int compare(Hello o1, Hello o2) {
        return o2.getWhen().compareTo(o1.getWhen()); // latest first
      }
    });
 
    return hellos;
  }
 
  @Override
  public Hello fromUsername(String username) {
    Query query = em.createNamedQuery("helloFromUsername");
    query.setParameter("username", username);
    Hello hello = null;
    try {
      hello = (Hello)query.getSingleResult();
    } catch (NoResultException ignored) {
    }
 
    return hello;
  }
 
  @TransactionAttribute
  @Override
  public Hello save(Hello hello) {
    hello = em.merge(hello);
    return hello;
  }
}

Напишите один фильтр Java Servlet 3 HelloFilter.java, который: 1. увеличивает счетчик при входе в систему, и 2. предоставляет экземпляр HelloBean на странице Java Server, которая скоро появится (полный класс здесь ):

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@WebFilter("/index.jsp")
public final class HelloFilter implements Filter {
 
  @EJB
  HelloDao  helloDao;
 
  @Override
  public void init(FilterConfig fConfig) throws ServletException {
  }
 
  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
  try {
    request.setAttribute("helloDao", helloDao);
 
    String username = ((HttpServletRequest)request).getRemoteUser();
    Hello hello = helloDao.fromUsername(username);
    if (hello == null) {
      hello = new Hello();
      hello.setUsername(username);
    } else {
      hello.setCounter(hello.getCounter()+1);
    }
    hello = helloDao.save(hello);
 
    chain.doFilter(request, response);
 
  } finally {
    request.removeAttribute("helloDao");
  }
  }
 
  @Override
  public void destroy() {
  }
}

NB. Выделено жирным шрифтом выше. Волшебная сантехника, выполненная нашим контейнером Java EE 6 Web Profile между всеми этими классами:

1
2
3
@PersistenceContext EntityManager em;
@EJB HelloDao helloDao;
@WebFilter('/index.jsp')

Напишите одну конфигурацию JPA persistence.xml (заполните здесь xml)

01
02
03
04
05
06
07
08
09
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
  <persistence-unit name="adventscloud-persist" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/DefaultDB</jta-data-source>
    <class>net.aequologica.adventscloud.Hello</class>
    <properties>
      <property name="eclipselink.ddl-generation" value="create-or-extend-tables" />
    </properties>
  </persistence-unit>
</persistence>

Напишите один файл web.xml, чтобы инициировать вход в систему при доступе пользователя к index.jsp и сообщить веб-приложению о наличии управляемой контейнером базы данных (заполните xml здесь ):

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?xml version="1.0" encoding="UTF-8"?>
<web-app
  version="3.0">
 
  <login-config>
    <auth-method>FORM</auth-method>
  </login-config>
 
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>Protected Area</web-resource-name>
      <url-pattern>/index.jsp</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>Everyone</role-name>
    </auth-constraint>
  </security-constraint>
  <security-role>
    <description>All SAP NetWeaver Cloud users</description>
    <role-name>Everyone</role-name>
  </security-role>
 
  <resource-ref>
    <res-ref-name>jdbc/DefaultDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
  </resource-ref>
 
</web-app>

Опять же, NB. Выделено жирным шрифтом дальнейшая волшебная сантехника:

1
2
3
<jta-data-source>jdbc/DefaultDB</jta-data-source>
<class>net.aequologica.adventscloud.Hello</class>
<res-ref-name>jdbc/DefaultDB</res-ref-name>

Наконец, напишите одну страницу java-сервера index.jsp, которая отображает все «hellos» (полная страница здесь ):

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<%@ taglib prefix="c"   uri="http://java.sun.com/jstl/core_rt" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt_rt" %>
<!DOCTYPE html>
<html>
  <head>
    <title>adventscloud</title>
  </head>
  <body>
 
  <table>
    <tbody>
      <c:forEach var="hello" items="${requestScope.helloDao.all}" varStatus="status">
        <tr>
          <td><fmt:formatDate type="both" value="${hello.when}" /></td>
          <td>${hello.counter}</td>
          <td>hello<c:if test = "${hello.counter > 1}">(s)</c:if> from</td>
          <td>${hello.username}</td>
        </tr>
      </c:forEach>
    </tbody>
  </table
 
  </body>
 
</html>

Мы почти закончили … две последние вещи: 1. ад classpath и 2. генерация метамодели JPA 2.0 с javac -процессором.

1. Classpath ад.

Чтобы скомпилировать все это, вам нужно как-то иметь следующие jar-файлы на classpath:

  группа |  артефакт |  версия
 javax.persistence: постоянство-API :> = 1,0 
 javax.ejb: ejb-api :> = 3.0 
 javax.servlet: javax.servlet-api :> = 3.0 
 javax.servlet: jstl :> = 1.2 

Конечно, самый простой способ — объявить эти зависимости в проекте maven, подобном моему , но если вы не любите maven, я потратил время на гиперссылку на jar-файлы выше на maven central, чтобы сэкономить время на погоне за jar-файлами.

2. Генерация метамодели JPA 2.0 с помощью javac -процессора.

Наконец, сборка должна быть способна генерировать классы метамодели JPA 2.0 . Здесь я выбираю генератор eclipselink, поскольку в конечном итоге eclipselink является реализацией JPA, используемой SAP NetWeaver Cloud. Я считаю, что любой JPA 2.0-совместимый генератор должен делать эту работу также. Здесь также помогает maven со следующим фрагментом xml в разделе <build> <plugins> файла pom.xml:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
<plugin>
  <groupId>org.bsc.maven</groupId>
  <artifactId>maven-processor-plugin</artifactId>
  <version>2.1.0</version>
  <executions>
    <execution>
      <id>process</id>
      <goals>
         <goal>process</goal>
      </goals>
      <phase>generate-sources</phase>
      <configuration>
        <processors>
          <processor>org.eclipse.persistence.internal.jpa.modelgen.CanonicalModelProcessor</processor>
        </processors>
      </configuration>
    </execution>
  </executions>
</plugin>

Maven- averse может обратиться к документации eclipselink о генерации метамодели JPA 2.0 для альтернативных способов генерации классов метамодели JPA 2.0.

На данный момент у нас есть файл adventscloud.war, который должен дословно выполняться в любом контейнере, совместимом с Java EE 6 Web Profile .

Среди них — SAP NetWeaver Cloud. Вы можете взглянуть на приложение, запущенное в моей бесплатной пробной версии SAP NetWeaver Cloud . Это немного богаче, чем код, показанный в этом сообщении в блоге, с искрой щебетать наворотов и свистки. Следуйте GitHub ленты в приложении, если вас интересуют искры.

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

Ссылка: веб-профиль Java EE 6. На облаке. Легко. от нашего партнера по JCG Кристофа Тибо из блога Java Advent Calendar .