SPRING-SOURCE.RU | |
|
|
Для этого урока не плохо бы знать что такое GWT (Google Web Toolkit).
Напишу кратко, как я понимаю взаимосвязь GWT и Spring:
В каком месте происходит контакт GWT приложения с Spring приложением? Этот вопрос важен для людей, которые хотят начать использовать эти две технологии вместе. Ответ - это происходит на уровне сервисов. Для начала, разрабатывается отдельно приложение GWT без какой-либо связи со Spring, а потом мы присоединяем его к Spring. Давайте поясним эти два шага:
Это руководство пошагово рассказывает о том как разработать простое web приложение, используя Google Web Toolkit (GWT) для клиентской части, и Spring для серверной части. Web приложение будет выполнять CRUD операции к базе данных. В качестве слоя доступа к данным мы будем использовать Hibernate, как реализацию JPA, и для базы данных мы будем использовать Hypersonic. Конечно же, вы можете изменять конфигурацию и использовать все, что вы хотите. Развертывать web приложение мы будет на Apache — Tomcat. Также будем использовать maven.
Maven поставляется в двух вариантах, standalone с поддержкой командной строки, и как IDE (Eclipse и Netbeans) плагин. Разрабатывать web приложение мы будет с помощью Eclipse с Maven поддержкой.
Что нам понадобится:
Начнем:
Если у кого-то не работает плагин для Eclipse, ту же операцию можно сделать и из командной строки, набрав:
mvn archetype:generate \ -DarchetypeGroupId=org.codehaus.mojo \ -DarchetypeArtifactId=gwt-maven-plugin \ -DgroupId=com.javacodegeeks \ -DartifactId=gwtspring
После этого зайдите в каталог и наберите mvn eclipse:eclipse, при этом вы спишите из интернета ненужные библиотеки. Теперь вы сможете импортировать ваш проект в среду разработки Eclipse.
Давайте рассмотрим структуру проекта Maven GWT:
Для того, чтобы правильно интегрировать Spring и GWT, мы должны предоставить web приложению все необходимые библиотеки. Откройте графический редактор «pom.xml» и выполните следующие действия:
Group Id | Artifact Id | Version |
org.springframework | spring-orm | ${org.springframework.version} |
org.springframework | spring-web | ${org.springframework.version} |
org.hibernate | hibernate-core | ${org.hibernate.version} |
org.hibernate | hibernate-annotations | ${org.hibernate.version} |
org.hibernate | hibernate-entitymanager | ${org.hibernate.version} |
org.hibernate.javax.persistence | hibernate-jpa-2.0-api | 1.0.0.Final |
org.slf4j | slf4j-log4j12 | 1.5.8 |
org.hsqldb | hsqldb | 1.8.0.10 |
c3p0 | c3p0 | 0.9.1.2 |
Обратите внимание, что возможны проблемы с версиями артефактов. Если у вас случилось так, что версия отсутствует в репозитории, то решать ее вам придется самим.
Не все библиотеки доступны через публичные репозитории. В нашем случае мы должны создать «lib» директорию в «/src/main/webapp/WEB-INF» и положить туда «spring4gwt-0.0.1.jar» для перехвата RPC вызовов между клиентом и сервером и трансформировать их в Spring обслуживание сервисов.
Давайте добавим в web.xml файл следующее:
<listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <servlet> <servlet-name>springGwtRemoteServiceServlet</servlet-name> <servlet-class>org.spring4gwt.server.SpringGwtRemoteServiceServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>springGwtRemoteServiceServlet</servlet-name> <url-pattern>/com.javacodegeeks.gwtspring.Application/springGwtServices/*</url-pattern> </servlet-mapping>
Заметьте, что:
Следующим шагом будет создание «persistence.xml» файла для описания соединения с базой данных, используя JPA. Этот файл должен находиться внутри META-INF директории, которая доступна web приложению во время выполнения (в classpath). Для выполнения этих требований мы должны создать META-INF директорию в /src/main/resources. Не забываем создать в этой директории файл «persistence.xml» и заполнить его, как указано ниже:
<persistence 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" version="2.0"> <persistence-unit name="MyPersistenceUnit" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="hibernate.hbm2ddl.auto" value="update" /> <property name="hibernate.show_sql" value="false" /> <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" /> <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver" /> <property name="hibernate.connection.url" value="jdbc:hsqldb:mem:javacodegeeks" /> <property name="hibernate.connection.username" value="sa" /> <property name="hibernate.connection.password" value="" /> <property name="hibernate.c3p0.min_size" value="5" /> <property name="hibernate.c3p0.max_size" value="20" /> <property name="hibernate.c3p0.timeout" value="300" /> <property name="hibernate.c3p0.max_statements" value="50" /> <property name="hibernate.c3p0.idle_test_period" value="3000" /> </properties> </persistence-unit> </persistence>
Теперь давайте создадим applicationContext.xml файл, который будет управлять Spring контейнером. Создадим файл в /src/main/webapp/WEB-INF директории. Пример applicationContext.xml представлен ниже:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"> <context:component-scan base-package="com.javacodegeeks.gwtspring" /> <tx:annotation-driven /> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="MyPersistenceUnit" /> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> </beans>
Заметьте, что:
В последней части этого урока мы рассмотрим Data Transfer Object (DTO) для транспортировки данных между клиентом и сервером, Data Access Object (DAO), который используется для доступа к базе данных и Spring сервис, который предоставляет функциональность для GWT Web клиента.
DTO — это объект, который может быть использован как клиентом так и сервером, для этого вы должны создать «shared.dto» подпакет под вашим основным пакетом (в нашем случае это com.javacodegeeks.gwtspring) и поместить DTO здесь. Мы создадим EmployeeDTO, содержащий информацию для «работника»:
package com.javacodegeeks.gwtspring.shared.dto; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "EMPLOYEE") public class EmployeeDTO implements java.io.Serializable { private static final long serialVersionUID = 7440297955003302414L; @Id @Column(name="employee_id") private long employeeId; @Column(name="employee_name", nullable = false, length=30) private String employeeName; @Column(name="employee_surname", nullable = false, length=30) private String employeeSurname; @Column(name="job", length=50) private String job; public EmployeeDTO() { } public EmployeeDTO(int employeeId) { this.employeeId = employeeId; } public EmployeeDTO(long employeeId, String employeeName, String employeeSurname, String job) { this.employeeId = employeeId; this.employeeName = employeeName; this.employeeSurname = employeeSurname; this.job = job; } public long getEmployeeId() { return employeeId; } public void setEmployeeId(long employeeId) { this.employeeId = employeeId; } public String getEmployeeName() { return employeeName; } public void setEmployeeName(String employeeName) { this.employeeName = employeeName; } public String getEmployeeSurname() { return employeeSurname; } public void setEmployeeSurname(String employeeSurname) { this.employeeSurname = employeeSurname; } public String getJob() { return job; } public void setJob(String job) { this.job = job; } }
DTO объект должен быть доступен для GWT клиента, для этого мы должны указать GWT компилятору, что нужно его обрабатывать. Давайте найдем GWT файл-модуль, имеющего имя «Application.gwt.xml», и находящегося в главном пакете (в нашем случае это com.javacodegeeks.gwtspring) и добавим в него следующие указания:
<!-- Specify the paths for translatable code --> <source path='client'/> <source path='shared'/>
DAO объект используется для доступа к базе данных и выполняет CRUD операции. Это серверный компонент и должен находиться в подпакете «server» в вашем проекте. Создайте «server.dao» подпакет в вашем главном пакете (в нашем случае это com.javacodegeeks.gwtspring) и разместите здесь DAO. Пример DAO представлен ниже:
package com.javacodegeeks.gwtspring.server.dao; import javax.annotation.PostConstruct; import javax.persistence.EntityManagerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import com.javacodegeeks.gwtspring.shared.dto.EmployeeDTO; @Repository("employeeDAO") public class EmployeeDAO extends JpaDAO<Long, EmployeeDTO> { @Autowired EntityManagerFactory entityManagerFactory; @PostConstruct public void init() { super.setEntityManagerFactory(entityManagerFactory); } }
Как вы можете видеть EmployeeDAO расширяет базовый DAO класс (JpaDAO). EmployeeDAO класс может содержать определенные запросы относительно EmployeeDTO объекта, но все CRUD операции могут быть обработаны в базовом DAO классе (JpaDAO). Разместите JpaDAO класс на тот же уровень, что и EmployeeDAO класс, под «dao» подпакете. Ниже представлен JpaDAO класс:
package com.javacodegeeks.gwtspring.server.dao; import java.lang.reflect.ParameterizedType; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.PersistenceException; import javax.persistence.Query; import org.springframework.orm.jpa.JpaCallback; import org.springframework.orm.jpa.support.JpaDaoSupport; public abstract class JpaDAO<K, E> extends JpaDaoSupport { protected Class<E> entityClass; @SuppressWarnings("unchecked") public JpaDAO() { ParameterizedType genericSuperclass = (ParameterizedType) getClass() .getGenericSuperclass(); this.entityClass = (Class<E>) genericSuperclass .getActualTypeArguments()[1]; } public void persist(E entity) { getJpaTemplate().persist(entity); } public void remove(E entity) { getJpaTemplate().remove(entity); } public E merge(E entity) { return getJpaTemplate().merge(entity); } public void refresh(E entity) { getJpaTemplate().refresh(entity); } public E findById(K id) { return getJpaTemplate().find(entityClass, id); } public E flush(E entity) { getJpaTemplate().flush(); return entity; } @SuppressWarnings("unchecked") public List<E> findAll() { Object res = getJpaTemplate().execute(new JpaCallback() { public Object doInJpa(EntityManager em) throws PersistenceException { Query q = em.createQuery("SELECT h FROM " + entityClass.getName() + " h"); return q.getResultList(); } }); return (List<E>) res; } @SuppressWarnings("unchecked") public Integer removeAll() { return (Integer) getJpaTemplate().execute(new JpaCallback() { public Object doInJpa(EntityManager em) throws PersistenceException { Query q = em.createQuery("DELETE FROM " + entityClass.getName() + " h"); return q.executeUpdate(); } }); } }
В конце мы создадим интерфейс сервиса и классы реализации для доступа GWT клиента. Интерфейс сервиса должен быть доступен как для клиента, так и сервера, поэтому все это должно лежать в подпакете «shared». Создайте подпакет «services» и поместите туда интерфейс сервиса. Вот пример интерфейса:
package com.javacodegeeks.gwtspring.shared.services; import com.google.gwt.user.client.rpc.RemoteService; import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; import com.javacodegeeks.gwtspring.shared.dto.EmployeeDTO; @RemoteServiceRelativePath("springGwtServices/employeeService") public interface EmployeeService extends RemoteService { public EmployeeDTO findEmployee(long employeeId); public void saveEmployee(long employeeId, String name, String surname, String jobDescription) throws Exception; public void updateEmployee(long employeeId, String name, String surname, String jobDescription) throws Exception; public void saveOrUpdateEmployee(long employeeId, String name, String surname, String jobDescription) throws Exception; public void deleteEmployee(long employeeId) throws Exception; }
Заметье, что:
Реализация класса сервиса является серверным компонентом, поэтому мы должны расположить его в подпакете «server» в нашем проекте. Создайте подпакет «services» и разместите его там. Вот пример реализации класса сервиса:
package com.javacodegeeks.gwtspring.server.services; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.javacodegeeks.gwtspring.server.dao.EmployeeDAO; import com.javacodegeeks.gwtspring.shared.dto.EmployeeDTO; import com.javacodegeeks.gwtspring.shared.services.EmployeeService; @Service("employeeService") public class EmployeeServiceImpl implements EmployeeService { @Autowired private EmployeeDAO employeeDAO; @PostConstruct public void init() throws Exception { } @PreDestroy public void destroy() { } public EmployeeDTO findEmployee(long employeeId) { return employeeDAO.findById(employeeId); } @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class) public void saveEmployee(long employeeId, String name, String surname, String jobDescription) throws Exception { EmployeeDTO employeeDTO = employeeDAO.findById(employeeId); if(employeeDTO == null) { employeeDTO = new EmployeeDTO(employeeId, name,surname, jobDescription); employeeDAO.persist(employeeDTO); } } @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class) public void updateEmployee(long employeeId, String name, String surname, String jobDescription) throws Exception { EmployeeDTO employeeDTO = employeeDAO.findById(employeeId); if(employeeDTO != null) { employeeDTO.setEmployeeName(name); employeeDTO.setEmployeeSurname(surname); employeeDTO.setJob(jobDescription); } } @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class) public void deleteEmployee(long employeeId) throws Exception { EmployeeDTO employeeDTO = employeeDAO.findById(employeeId); if(employeeDTO != null) employeeDAO.remove(employeeDTO); } @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class) public void saveOrUpdateEmployee(long employeeId, String name, String surname, String jobDescription) throws Exception { EmployeeDTO employeeDTO = new EmployeeDTO(employeeId, name,surname, jobDescription); employeeDAO.merge(employeeDTO); } }
Заметье, что:
Мы почти закончили. Давайте приступим к разработке GWT пользовательского интерфейса для доступа к нашему Spring сервису.
Давайте перейдем к точке входа нашего GWT приложения. Файл должен называться «Application.java» и расположен в подпакете «client» в главном пакете. Вот этот класс:
package com.javacodegeeks.gwtspring.client; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyUpEvent; import com.google.gwt.event.dom.client.KeyUpHandler; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.DialogBox; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.VerticalPanel; import com.javacodegeeks.gwtspring.shared.dto.EmployeeDTO; import com.javacodegeeks.gwtspring.shared.services.EmployeeServiceAsync; /** * Entry point classes define <code>onModuleLoad()</code>. */ public class Application implements EntryPoint { /** * The message displayed to the user when the server cannot be reached or * returns an error. */ private static final String SERVER_ERROR = "An error occurred while " + "attempting to contact the server. Please check your network " + "connection and try again. The error is : "; /** * Create a remote service proxy to talk to the server-side Employee service. */ private final EmployeeServiceAsync employeeService = EmployeeServiceAsync.Util.getInstance(); /** * This is the entry point method. */ public void onModuleLoad() { final Button saveOrUpdateButton = new Button("SaveOrUpdate"); final Button retrieveButton = new Button("Retrieve"); final TextBox employeeInfoField = new TextBox(); employeeInfoField.setText("Employee Info"); final TextBox employeeIdField = new TextBox(); final Label errorLabel = new Label(); // We can add style names to widgets saveOrUpdateButton.addStyleName("sendButton"); retrieveButton.addStyleName("sendButton"); // Add the nameField and sendButton to the RootPanel // Use RootPanel.get() to get the entire body element RootPanel.get("employeeInfoFieldContainer").add(employeeInfoField); RootPanel.get("updateEmployeeButtonContainer").add(saveOrUpdateButton); RootPanel.get("employeeIdFieldContainer").add(employeeIdField); RootPanel.get("retrieveEmployeeButtonContainer").add(retrieveButton); RootPanel.get("errorLabelContainer").add(errorLabel); // Focus the cursor on the name field when the app loads employeeInfoField.setFocus(true); employeeInfoField.selectAll(); // Create the popup dialog box final DialogBox dialogBox = new DialogBox(); dialogBox.setText("Remote Procedure Call"); dialogBox.setAnimationEnabled(true); final Button closeButton = new Button("Close"); // We can set the id of a widget by accessing its Element closeButton.getElement().setId("closeButton"); final Label textToServerLabel = new Label(); final HTML serverResponseLabel = new HTML(); VerticalPanel dialogVPanel = new VerticalPanel(); dialogVPanel.addStyleName("dialogVPanel"); dialogVPanel.add(new HTML("<b>Sending request to the server:</b>")); dialogVPanel.add(textToServerLabel); dialogVPanel.add(new HTML(" <b>Server replies:</b>")); dialogVPanel.add(serverResponseLabel); dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT); dialogVPanel.add(closeButton); dialogBox.setWidget(dialogVPanel); // Add a handler to close the DialogBox closeButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { dialogBox.hide(); saveOrUpdateButton.setEnabled(true); saveOrUpdateButton.setFocus(true); retrieveButton.setEnabled(true); } }); // Create a handler for the saveOrUpdateButton and employeeInfoField class SaveOrUpdateEmployeeHandler implements ClickHandler, KeyUpHandler { /** * Fired when the user clicks on the saveOrUpdateButton. */ public void onClick(ClickEvent event) { sendEmployeeInfoToServer(); } /** * Fired when the user types in the employeeInfoField. */ public void onKeyUp(KeyUpEvent event) { if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) { sendEmployeeInfoToServer(); } } /** * Send the employee info from the employeeInfoField to the server and wait for a response. */ private void sendEmployeeInfoToServer() { // First, we validate the input. errorLabel.setText(""); String textToServer = employeeInfoField.getText(); // Then, we send the input to the server. saveOrUpdateButton.setEnabled(false); textToServerLabel.setText(textToServer); serverResponseLabel.setText(""); String[] employeeInfo = textToServer.split(" "); long employeeId = Long.parseLong(employeeInfo[0]); String employeeName = employeeInfo[1]; String employeeSurname = employeeInfo[2]; String employeeJobTitle = employeeInfo[3]; employeeService.saveOrUpdateEmployee(employeeId, employeeName, employeeSurname, employeeJobTitle, new AsyncCallback<Void>() { public void onFailure(Throwable caught) { // Show the RPC error message to the user dialogBox .setText("Remote Procedure Call - Failure"); serverResponseLabel .addStyleName("serverResponseLabelError"); serverResponseLabel.setHTML(SERVER_ERROR + caught.toString()); dialogBox.center(); closeButton.setFocus(true); } public void onSuccess(Void noAnswer) { dialogBox.setText("Remote Procedure Call"); serverResponseLabel .removeStyleName("serverResponseLabelError"); serverResponseLabel.setHTML("OK"); dialogBox.center(); closeButton.setFocus(true); } }); } } // Create a handler for the retrieveButton and employeeIdField class RetrieveEmployeeHandler implements ClickHandler, KeyUpHandler { /** * Fired when the user clicks on the retrieveButton. */ public void onClick(ClickEvent event) { sendEmployeeIdToServer(); } /** * Fired when the user types in the employeeIdField. */ public void onKeyUp(KeyUpEvent event) { if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) { sendEmployeeIdToServer(); } } /** * Send the id from the employeeIdField to the server and wait for a response. */ private void sendEmployeeIdToServer() { // First, we validate the input. errorLabel.setText(""); String textToServer = employeeIdField.getText(); // Then, we send the input to the server. retrieveButton.setEnabled(false); textToServerLabel.setText(textToServer); serverResponseLabel.setText(""); employeeService.findEmployee(Long.parseLong(textToServer), new AsyncCallback<EmployeeDTO>() { public void onFailure(Throwable caught) { // Show the RPC error message to the user dialogBox .setText("Remote Procedure Call - Failure"); serverResponseLabel .addStyleName("serverResponseLabelError"); serverResponseLabel.setHTML(SERVER_ERROR + caught.toString()); dialogBox.center(); closeButton.setFocus(true); } public void onSuccess(EmployeeDTO employeeDTO) { dialogBox.setText("Remote Procedure Call"); serverResponseLabel .removeStyleName("serverResponseLabelError"); if(employeeDTO != null) serverResponseLabel.setHTML("Employee Information Id : " + employeeDTO.getEmployeeId() + " Name : " + employeeDTO.getEmployeeName() + " Surname : " + employeeDTO.getEmployeeSurname() + " Job Title : " + employeeDTO.getJob()); else serverResponseLabel.setHTML("No employee with the specified id found"); dialogBox.center(); closeButton.setFocus(true); } }); } } // Add a handler to send the employee info to the server SaveOrUpdateEmployeeHandler saveOrUpdateEmployeehandler = new SaveOrUpdateEmployeeHandler(); saveOrUpdateButton.addClickHandler(saveOrUpdateEmployeehandler); employeeInfoField.addKeyUpHandler(saveOrUpdateEmployeehandler); // Add a handler to send the employee id to the server RetrieveEmployeeHandler retrieveEmployeehandler = new RetrieveEmployeeHandler(); retrieveButton.addClickHandler(retrieveEmployeehandler); employeeIdField.addKeyUpHandler(retrieveEmployeehandler); } }
Как вы можете видеть, вызов Spring сервиса выполняется так же, как классические вызовы GWT сервисов, прозрачно для клиента.
В конце мы будем работать с «Application.html» файлом.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <!-- The HTML 4.01 Transitional DOCTYPE declaration--> <!-- above set at the top of the file will set --> <!-- the browser's rendering engine into --> <!-- "Quirks Mode". Replacing this declaration --> <!-- with a "Standards Mode" doctype is supported, --> <!-- but may lead to some differences in layout. --> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <!-- --> <!-- Any title is fine --> <!-- --> <title><a href="http://www.springsource.org/">Spring</a> <a href="http://code.google.com/webtoolkit/">GWT</a> Web Application Starter Project</title> <!-- --> <!-- This script loads your compiled module. --> <!-- If you add any <a href="http://code.google.com/webtoolkit/">GWT</a> meta tags, they must --> <!-- be added before this line. --> <!-- --> <script type="text/javascript" language="javascript" src="com.javacodegeeks.gwtspring.Application.nocache.js"></script> </head> <!-- --> <!-- The body can have arbitrary html, or --> <!-- you can leave the body empty if you want --> <!-- to create a completely dynamic UI. --> <!-- --> <body> <!-- OPTIONAL: include this if you want history support --> <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe> <!-- RECOMMENDED if your web app will not function without JavaScript enabled --> <noscript> <div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif"> Your web browser must have JavaScript enabled in order for this application to display correctly. </div> </noscript> <h1 align="center"><a href="http://www.springsource.org/">Spring</a> <a href="http://code.google.com/webtoolkit/">GWT</a> Web Application Starter Project</h1> <table align="center"> <tr> <td colspan="2" style="font-weight:bold;">Please enter employee info (id name surname job):</td> </tr> <tr> <td id="employeeInfoFieldContainer"></td> <td id="updateEmployeeButtonContainer"></td> </tr> <tr> <tr> <td colspan="2" style="font-weight:bold;">Please enter employee id:</td> </tr> <tr> <td id="employeeIdFieldContainer"></td> <td id="retrieveEmployeeButtonContainer"></td> </tr> <tr> <td colspan="2" style="color:red;" id="errorLabelContainer"></td> </tr> </table> </body> </html>
Чтобы построить приложение нажмите Run As — Maven package. Для развертывания приложения просто скопируйте «war» файл из «target» директории в Apache — Tomcat «webapps» директорию. Заупскайте приложение, набрав в браузере строку (application_name замените на имя приложения):
http://localhost:8080/{application_name}/
Copyright © 2024 |