Это то, что я всегда думал. Ну, не больше, сейчас. Позвольте мне поделиться своим опытом.
Несколько недель назад я начал думать о переносе устаревшего приложения 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 version = "2.0" xmlns = "http://java.sun.com/xml/ns/persistence" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" > < 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 xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 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 .