js webapp://_Project Student:维护Webapp(只读)
js webapp://
這是Project Student的一部分。 其他職位包括具有Jersey的 Web服務(wù) 客戶端,具有Jersey的 Web服務(wù)服務(wù)器 , 業(yè)務(wù)層 , 具有Spring數(shù)據(jù)的持久性 ,分片集成測(cè)試數(shù)據(jù) , Webservice集成和JPA標(biāo)準(zhǔn)查詢 。
當(dāng)我開(kāi)始這個(gè)項(xiàng)目時(shí),我有四個(gè)目標(biāo)。 他們沒(méi)有特別的順序:
- 了解jQuery和其他AJAX技術(shù)。 為此,我需要一個(gè)了解的REST服務(wù)器,
- 捕獲最近獲得的有關(guān)球衣和掛毯的知識(shí),
- 創(chuàng)建一個(gè)我可以用來(lái)了解其他技術(shù)(例如spring MVC,restlet,netty)的框架,以及
- 在工作面試中有什么要討論的
如果對(duì)其他人有用–太好了! 這就是為什么它在Apache許可下可用。
(不言而喻,可接受的用途不包括在沒(méi)有適當(dāng)歸因的情況下將“ Project Student”變成學(xué)生項(xiàng)目!)
學(xué)習(xí)AJAX的問(wèn)題是,我一開(kāi)始會(huì)不確定問(wèn)題的根源。 jQuery不好嗎? 不良的REST服務(wù)? 還有嗎 廣泛的單元和集成測(cè)試是一個(gè)好的開(kāi)始,但是始終會(huì)存在一些不確定性。
另一個(gè)考慮因素是,在現(xiàn)實(shí)世界中,我們經(jīng)常需要對(duì)數(shù)據(jù)庫(kù)的基本視圖。 它不會(huì)供公眾使用-當(dāng)我們遇到WTF時(shí)刻時(shí)僅供內(nèi)部使用。 它也可以用來(lái)維護(hù)我們不想通過(guò)公共界面管理的信息,例如下拉菜單中的值。
對(duì)此可以稍作調(diào)整,以提供適度的可伸縮性。 將大型服務(wù)器用于數(shù)據(jù)庫(kù)和REST服務(wù),然后讓N臺(tái)前端服務(wù)器運(yùn)行常規(guī)的Web應(yīng)用程序,充當(dāng)用戶和REST服務(wù)之間的中介。 前端服務(wù)器可以是相當(dāng)輕量的,并且可以根據(jù)需要旋轉(zhuǎn)。 將緩存服務(wù)器放置在前端和REST服務(wù)器之間的加分點(diǎn),因?yàn)閷⒆x取壓倒性的點(diǎn)擊量。
這種方法無(wú)法擴(kuò)展到Amazon或Facebook的規(guī)模,但是對(duì)于許多站點(diǎn)來(lái)說(shuō)已經(jīng)足夠了。
維護(hù)Webapp
這將我們帶到了webapp onion的可選層–一個(gè)常規(guī)的webapp,充當(dāng)REST服務(wù)的前端。 由于各種原因,我在應(yīng)用程序中使用Tapestry 5 ,但這是一個(gè)任意決定,我不會(huì)花很多時(shí)間研究Tapestry特定的代碼。
您可以使用創(chuàng)建新的掛毯項(xiàng)目
$ mvn archetype:generate -DarchetypeCatalog=http://tapestry.apache.org我已經(jīng)在http://jumpstart.doublenegative.com.au/jumpstart/examples/找到了有價(jià)值的示例。 在適當(dāng)?shù)牡胤?#xff0c;我會(huì)注明出處。
稍后,我還將創(chuàng)建webapp的第二個(gè)可選層–使用Selenium和WebDriver (即Selenium 2.0)進(jìn)行功能和回歸測(cè)試。
局限性
只讀 –分解webapp需要進(jìn)行大量工作,因此初始版本將僅提供對(duì)簡(jiǎn)單表的只讀訪問(wèn)。 沒(méi)有更新,沒(méi)有一對(duì)多映射。
用戶身份驗(yàn)證 –尚未進(jìn)行身份驗(yàn)證的工作。
加密 -尚未對(duì)通信進(jìn)行加密。
數(shù)據(jù)庫(kù)鎖 –我們?cè)贖ibernate版本中使用機(jī)會(huì)鎖定,而不是顯式數(shù)據(jù)庫(kù)鎖定。 安全說(shuō)明:根據(jù)最少公開(kāi)的原則,除非需要,否則我們不想使該版本可見(jiàn)。 一個(gè)好的規(guī)則是,您將看到它是否請(qǐng)求一個(gè)特定的對(duì)象,但看不到列表中的對(duì)象。
REST客戶端 -每種類型的默認(rèn)GET處理程序非常粗糙-僅返回對(duì)象列表。 我們需要一個(gè)更復(fù)雜的響應(yīng)(例如,記錄數(shù),開(kāi)始和結(jié)束索引,狀態(tài)碼等),并將讓UI驅(qū)動(dòng)它。 目前,我們真正需要的只是一個(gè)計(jì)數(shù),我們可以只請(qǐng)求列表并計(jì)數(shù)元素的數(shù)量。
目標(biāo)
我們需要一個(gè)列出數(shù)據(jù)庫(kù)中所有課程的頁(yè)面。 它不必?fù)?dān)心分頁(yè),排序等問(wèn)題。它應(yīng)該具有用于??編輯和刪除記錄的鏈接(可能是無(wú)效的)。 它不需要添加新課程的鏈接。
該頁(yè)面應(yīng)如下所示:
課程模板
Tapestry頁(yè)面上列出的課程很簡(jiǎn)單–它基本上只是修飾的值網(wǎng)格 。
(有關(guān)Layout.tml等信息,請(qǐng)參見(jiàn)掛毯原型。)
<html t:type="layout" title="Course List"t:sidebarTitle="Framework Version"xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd"xmlns:p="tapestry:parameter"><!-- Most of the page content, including <head>, <body>, etc. tags, comes from Layout.tml --><t:zone t:id="zone"> <p>"Course" page</p><t:grid source="courses" row="course" include="uuid,name,creationdate" add="edit,delete"><p:name><t:pagelink page="CourseEditor" context="course.uuid">${course.name}</t:pagelink></p:name><p:editcell><t:actionlink t:id="edit" context="course.uuid">Edit</t:actionlink></p:editcell><p:deletecell><t:actionlink t:id="delete" context="course.uuid">Delete</t:actionlink></p:deletecell><p:empty><p>There are no courses to display; you can <t:pagelink page="Course/Editor" parameters="{ 'mode':'create', 'courseUuid':null }">add some</t:pagelink>.</p></p:empty></t:grid></t:zone><p:sidebar><p>[<t:pagelink page="Index">Index</t:pagelink>]<br/>[<t:pagelink page="Course/List">Courses</t:pagelink>]</p></p:sidebar> </html>具有的屬性文件
title=Courses delete-course=Delete course?我已經(jīng)包括了用于編輯和刪除的操作鏈接,但是它們不起作用。
GridDataSources
我們的頁(yè)面需要顯示值的來(lái)源。 這需要兩個(gè)類。 第一個(gè)定義了上面使用的課程屬性。
package com.invariantproperties.sandbox.student.maintenance.web.tables;import com.invariantproperties.sandbox.student.business.CourseFinderService;public class GridDataSources {// Screen fields@Propertyprivate GridDataSource courses;// Generally useful bits and pieces@Injectprivate CourseFinderService courseFinderService;@InjectComponentprivate Grid grid;// The codevoid setupRender() {courses = new CoursePagedDataSource(courseFinderService);} }實(shí)際的實(shí)現(xiàn)是
package com.invariantproperties.sandbox.student.maintenance.web.tables;import com.invariantproperties.sandbox.student.business.CourseFinderService; import com.invariantproperties.sandbox.student.domain.Course; import com.invariantproperties.sandbox.student.maintenance.query.SortCriterion; import com.invariantproperties.sandbox.student.maintenance.query.SortDirection;public class CoursePagedDataSource implements GridDataSource {private int startIndex;private List<Course> preparedResults;private final CourseFinderService courseFinderService;public CoursePagedDataSource(CourseFinderService courseFinderService) {this.courseFinderService = courseFinderService;}@Overridepublic int getAvailableRows() {long count = courseFinderService.count();return (int) count;}@Overridepublic void prepare(final int startIndex, final int endIndex, final List<SortConstraint> sortConstraints) {// Get a page of courses - ask business service to find them (from the// database)// List<SortCriterion> sortCriteria = toSortCriteria(sortConstraints);// preparedResults = courseFinderService.findCourses(startIndex,// endIndex - startIndex + 1, sortCriteria);preparedResults = courseFinderService.findAllCourses();this.startIndex = startIndex;}@Overridepublic Object getRowValue(final int index) {return preparedResults.get(index - startIndex);}@Overridepublic Class<Course> getRowType() {return Course.class;}/*** Converts a list of Tapestry's SortConstraint to a list of our business* tier's SortCriterion. The business tier does not use SortConstraint* because that would create a dependency on Tapestry.*/private List<SortCriterion> toSortCriteria(List<SortConstraint> sortConstraints) {List<SortCriterion> sortCriteria = new ArrayList<>();for (SortConstraint sortConstraint : sortConstraints) {String propertyName = sortConstraint.getPropertyModel().getPropertyName();SortDirection sortDirection = SortDirection.UNSORTED;switch (sortConstraint.getColumnSort()) {case ASCENDING:sortDirection = SortDirection.ASCENDING;break;case DESCENDING:sortDirection = SortDirection.DESCENDING;break;default:}SortCriterion sortCriterion = new SortCriterion(propertyName, sortDirection);sortCriteria.add(sortCriterion);}return sortCriteria;} }應(yīng)用模塊
現(xiàn)在有了GridDataSource,我們可以看到它的需求– CourseFinderService。 雖然存在Tapestry-Spring集成,但我們希望保持維護(hù)Webapp盡可能薄,所以現(xiàn)在我們使用標(biāo)準(zhǔn)Tapestry注入。
package com.invariantproperties.sandbox.student.maintenance.web.services;import com.invariantproperties.sandbox.student.business.CourseFinderService; import com.invariantproperties.sandbox.student.business.CourseManagerService; import com.invariantproperties.sandbox.student.maintenance.service.impl.CourseFinderServiceTapestryImpl; import com.invariantproperties.sandbox.student.maintenance.service.impl.CourseManagerServiceTapestryImpl;/*** This module is automatically included as part of the Tapestry IoC Registry,* it's a good place to configure and extend Tapestry, or to place your own* service definitions.*/ public class AppModule {public static void bind(ServiceBinder binder) {binder.bind(CourseFinderService.class, CourseFinderServiceTapestryImpl.class);binder.bind(CourseManagerService.class, CourseManagerServiceTapestryImpl.class);}.... }請(qǐng)注意,我們正在將標(biāo)準(zhǔn)CourseFinderService接口與掛毯特定的實(shí)現(xiàn)一起使用。 這意味著我們可以直接使用標(biāo)準(zhǔn)實(shí)現(xiàn),只需要對(duì)配置文件進(jìn)行一點(diǎn)改動(dòng)即可!
CourseFinderServiceTapestryImpl
CourseFinderService接口的本地實(shí)現(xiàn)必須使用REST客戶端而不是Spring Data實(shí)現(xiàn)。 使用較早使用的由外而內(nèi)的方法,Tapestry模板的需求應(yīng)驅(qū)動(dòng)服務(wù)實(shí)現(xiàn)的需求,進(jìn)而驅(qū)動(dòng)REST客戶端和服務(wù)器的需求。
package com.invariantproperties.sandbox.student.maintenance.service.impl;public class CourseFinderServiceTapestryImpl implements CourseFinderService {private final CourseFinderRestClient finder;public CourseFinderServiceTapestryImpl() {// resource should be loaded as tapestry resourcefinal String resource = "http://localhost:8080/student-ws-webapp/rest/course/";finder = new CourseFinderRestClientImpl(resource);// load some initial datainitCache(new CourseManagerRestClientImpl(resource));}@Overridepublic long count() {// FIXME: grossly inefficient but good enough for now.return finder.getAllCourses().length;}@Overridepublic long countByTestRun(TestRun testRun) {// FIXME: grossly inefficient but good enough for now.return finder.getAllCourses().length;}@Overridepublic Course findCourseById(Integer id) {// unsupported operation!throw new ObjectNotFoundException(id);}@Overridepublic Course findCourseByUuid(String uuid) {return finder.getCourse(uuid);}@Overridepublic List<Course> findAllCourses() {return Arrays.asList(finder.getAllCourses());}@Overridepublic List<Course> findCoursesByTestRun(TestRun testRun) {return Collections.emptyList();}// method to load some test data into the database.private void initCache(CourseManagerRestClient manager) {manager.createCourse("physics 101");manager.createCourse("physics 201");manager.createCourse("physics 202");} }我們的JPA Criteria查詢可以快速計(jì)數(shù),但是我們的REST客戶端尚不支持。
結(jié)語(yǔ)
完成艱苦的工作后,我們將獲得一個(gè)維護(hù)文件.war。 我們可以使用webservice .war在我們的應(yīng)用服務(wù)器上部署它,也可以不部署。 除了Web服務(wù)的臨時(shí)硬編碼URL外,這兩個(gè).war文件沒(méi)有理由必須位于同一系統(tǒng)上。
我們首先應(yīng)該去http:// localhost:8080 / student-maintenance-webapp / course / list。 我們應(yīng)該看到如上所示的簡(jiǎn)短課程列表。 (在那種情況下,我已經(jīng)重新啟動(dòng)了webapp三次,因此每個(gè)條目都會(huì)重復(fù)三倍。)
現(xiàn)在,我們應(yīng)該訪問(wèn)位于http:// localhost:8080 / student-ws-webapp / rest / course的webservice webapp,并驗(yàn)證我們是否也可以通過(guò)瀏覽器獲取數(shù)據(jù)。 經(jīng)過(guò)一些清理后,我們應(yīng)該看到:
{"course":[{"creationDate":"2013-12-28T14:40:21.369-07:00","uuid":"500069e4-444d-49bc-80f0-4894c2d13f6a","version":"0","name":"physics 101"},{"creationDate":"2013-12-28T14:40:21.777-07:00","uuid":"54001b2a-abbb-4a75-a289-e1f09173fa04","version":"0","name":"physics 201"},{"creationDate":"2013-12-28T14:40:21.938-07:00","uuid":"cfaf892b-7ead-4d64-8659-8f87756bed62","version":"0","name":"physics 202"},{"creationDate":"2013-12-28T16:17:54.608-07:00","uuid":"d29735ff-f614-4979-a0de-e1d134e859f4","version":"0","name":"physics 101"},....] }源代碼
- 源代碼位于https://github.com/beargiles/project-student [github]和http://beargiles.github.io/project-student/ [github頁(yè)面]。
翻譯自: https://www.javacodegeeks.com/2014/01/project-student-maintenance-webapp-read-only.html
js webapp://
總結(jié)
以上是生活随笔為你收集整理的js webapp://_Project Student:维护Webapp(只读)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: (linux if -gt)
- 下一篇: 奇迹单机安卓版仿pc(奇迹单机安卓版)