摘要:今天的天學(xué)習(xí)種新技術(shù)挑戰(zhàn),我決定使用框架和開(kāi)發(fā)一個(gè)單頁(yè)面應(yīng)用。應(yīng)用我們將開(kāi)發(fā)一個(gè)社交化書(shū)簽應(yīng)用,允許用戶(hù)提交和分享鏈接。在元素中使用指令,意味著在整個(gè)中可用。我使用作為該應(yīng)用的模塊名。
編者注:我們發(fā)現(xiàn)了有趣的系列文章《30天學(xué)習(xí)30種新技術(shù)》,正在翻譯,一天一篇更新,年終禮包。下面是第22天的內(nèi)容。
今天的《30天學(xué)習(xí)30種新技術(shù)》挑戰(zhàn),我決定使用Spring框架、MongoDB和AngularJS開(kāi)發(fā)一個(gè)單頁(yè)面應(yīng)用。我很熟悉Spring和MongoDB,但是我沒(méi)用配合Spring使用過(guò)AngularJS。今天我們將開(kāi)發(fā)一個(gè)社交化的書(shū)簽應(yīng)用,類(lèi)似我們幾天前用EmberJS開(kāi)發(fā)的那個(gè)。我在第二天介紹了AngularJS的基本知識(shí),請(qǐng)參閱我的文章獲取更多信息。本文使用最新版的Spring框架,即3.2.5.RELEASE,我們將不使用XML(連web.xml也不用)。我們將通過(guò)Spring的annotation支持來(lái)配置一切。我們將使用Spring MVC來(lái)創(chuàng)建一個(gè)REST后端。同時(shí)將AngularJS作為客戶(hù)端的MVC框架來(lái)開(kāi)發(fā)應(yīng)用的前端。
應(yīng)用我們將開(kāi)發(fā)一個(gè)社交化書(shū)簽應(yīng)用,允許用戶(hù)提交和分享鏈接。你可以在這里查看這個(gè)應(yīng)用。這個(gè)應(yīng)用可以做到:
當(dāng)用戶(hù)訪問(wèn)/時(shí),他會(huì)看到以提交時(shí)間排序的報(bào)道列表。
當(dāng)用戶(hù)訪問(wèn)某個(gè)書(shū)簽時(shí),例如#/stories/528b9a8ce4b0da0473622359,用戶(hù)會(huì)看到關(guān)于這個(gè)報(bào)道的信息,例如是誰(shuí)提交的,何時(shí)提交的,以及文章的摘要。AngularJS將發(fā)送一個(gè)REST化的GET請(qǐng)求(/api/v1/stories/528b9a8ce4b0da0473622359)來(lái)獲取全文。
最后,當(dāng)用戶(hù)通過(guò)#/stories/new提交新報(bào)道時(shí),會(huì)向REST后端發(fā)起一個(gè)POST請(qǐng)求,報(bào)道會(huì)被保存在MongoDB數(shù)據(jù)庫(kù)。用戶(hù)只需填寫(xiě)報(bào)道的URL。應(yīng)用將使用我們?cè)诘?6天開(kāi)發(fā)的Goose Extractor RESTful API獲取標(biāo)題、主要圖片和文章摘要,
前提基本的Java知識(shí)。安裝最新的JDK。你可以安裝OpenJDK 7和Oracle JDK 7。OpenShift支持 OpenJDK6 和 7。
基本的Spring知識(shí)。
注冊(cè)一個(gè)OpenShift賬號(hào)。注冊(cè)是完全免費(fèi)的,Red Hat給每個(gè)用戶(hù)三枚免費(fèi)的Gear,可以用Gear運(yùn)行你的應(yīng)用。在寫(xiě)作此文的時(shí)候,每個(gè)用戶(hù)能免費(fèi)使用總共 1.5 GB 內(nèi)存和 3 GB 硬盤(pán)空間。
安裝 rhc客戶(hù)端工具。rhc是ruby gem,因此你的機(jī)子上需要裝有 ruby 1.8.7以上版本。 只需輸入 sudo gem install rhc即可安裝 rhc 。如果你已經(jīng)安裝過(guò)了,確保是最新版。運(yùn)行sudo gem update rhc即可升級(jí)。關(guān)于配置rhc命令行工具的詳細(xì)信息,請(qǐng)參考: https://openshift.redhat.com/community/developers/rhc-client-tools-install
使用 rhc 的 setup 命令配置你的 OpenShift 賬號(hào)。這個(gè)命令會(huì)幫助你創(chuàng)建一個(gè)命名空間,同時(shí)將你的ssh公鑰上傳至 OpenShift 服務(wù)器。
Github倉(cāng)庫(kù)今天的示例應(yīng)用的代碼可從github取得。
第一步 創(chuàng)建Tomcat 7應(yīng)用創(chuàng)建新應(yīng)用,使用Tomcat 7和MongoDB
rhc create-app getbookmarks tomcat-7 mongodb-2
這會(huì)為我們創(chuàng)建一個(gè)應(yīng)用容器——gear,然后設(shè)置公開(kāi)的DNS,創(chuàng)建私有g(shù)it倉(cāng)庫(kù),最后利用你的Github倉(cāng)庫(kù)中的代碼來(lái)部署應(yīng)用。應(yīng)用可以通過(guò)http://getbookmarks-{domain-name}.rhcloud.com/訪問(wèn)。用你自己的OpenShift域名替換{domain-name} (域名有時(shí)也被稱(chēng)為命名空間)。
第二步 刪除模板代碼接著我們刪除OpenShift創(chuàng)建的模板代碼
cd getbookmarks git rm -rf src/main/webapp/*.jsp src/main/webapp/index.html src/main/webapp/images src/main/webapp/WEB-INF/web.xml git commit -am "deleted template files"
請(qǐng)注意我們同時(shí)也刪除了web.xml。
第三步 更新pom.xml用以下代碼替換pom.xml的內(nèi)容
4.0.0 getbookmarks getbookmarks war 1.0 getbookmarks UTF-8 1.7 1.7 org.springframework spring-webmvc 3.2.5.RELEASE org.springframework spring-tx 3.2.5.RELEASE org.springframework.data spring-data-mongodb 1.3.2.RELEASE org.codehaus.jackson jackson-mapper-asl 1.9.13 javax.servlet javax.servlet-api 3.1.0 provided openshift getbookmarks maven-war-plugin 2.4 `false webapps ROOT
上述pom.xml中:
我們?yōu)閟pring-webmvc、spring-mongodb、jackson和最新的servlet api添加了Maven依賴(lài)。
項(xiàng)目使用JDK 7代替JDK 6。
使用最新的Maven的war插件。為了避免由于web.xml不存在導(dǎo)致的構(gòu)建錯(cuò)誤,我們添加了一個(gè)配置選項(xiàng)。
修改之后,別忘了右擊Maven > Update Project來(lái)更新maven項(xiàng)目。
第四步 編寫(xiě) WebMvcConfig 和 AppConfig 類(lèi)創(chuàng)建com.getbookmarks.config包和WebMvcConfig類(lèi)。
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.view.json.MappingJacksonJsonView; @EnableWebMvc @ComponentScan(basePackageClasses = StoryResource.class) @Configuration public class WebMvcConfig{ }
接下來(lái)我們將創(chuàng)建AppConfig配置類(lèi)。Spring MongoDB有一個(gè)倉(cāng)庫(kù)概念,你在其中實(shí)現(xiàn)接口,然后Spring會(huì)生成相應(yīng)的代理類(lèi)。這使得編寫(xiě)倉(cāng)庫(kù)類(lèi)非常容易,也節(jié)省了大量的樣板代碼。Spring MongoDB允許我們通過(guò)@EnableMongoRepositories annotation 聲明激活Mongo倉(cāng)庫(kù)。
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.authentication.UserCredentials; import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.SimpleMongoDbFactory; import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; import com.getbookmarks.repository.StoryRepository; import com.mongodb.Mongo; @Configuration @EnableMongoRepositories(basePackageClasses = StoryRepository.class) public class ApplicationConfig { @Bean public MongoTemplate mongoTemplate() throws Exception { String openshiftMongoDbHost = System.getenv("OPENSHIFT_MONGODB_DB_HOST"); ` int openshiftMongoDbPort = Integer.parseInt(System.getenv("OPENSHIFT_MONGODB_DB_PORT")); String username = System.getenv("OPENSHIFT_MONGODB_DB_USERNAME"); String password = System.getenv("OPENSHIFT_MONGODB_DB_PASSWORD"); Mongo mongo = new Mongo(openshiftMongoDbHost, openshiftMongoDbPort); UserCredentials userCredentials = new UserCredentials(username, password); String databaseName = System.getenv("OPENSHIFT_APP_NAME"); MongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongo, databaseName, userCredentials); MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory); return mongoTemplate; } }第五步 編寫(xiě) GetBookmarksWebApplicationInitializer 類(lèi)
Servlet 3.0下,web.xml是可選的。通常,我們?cè)?b>web.xml中配置Spring WebMVC調(diào)度器,不過(guò)從Spring 3.1開(kāi)始,我們可以使用WebApplicationInitializer以編程方式配置了。Spring提供了ServletContainerInitializer接口的一個(gè)實(shí)現(xiàn) SpringServletContainerInitializer。SpringServletContainerInitializer類(lèi)將任務(wù)委派給你提供的org.springframework.web.WebApplicationInitializer實(shí)現(xiàn)。你只需實(shí)現(xiàn)一個(gè)方法WebApplicationInitializer#onStartup(ServletContext),傳遞需要初始化的ServletContext。
import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration.Dynamic; import org.springframework.web.WebApplicationInitializer; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; public class GetBookmarksWebApplicationInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { AnnotationConfigWebApplicationContext webApplicationContext = new AnnotationConfigWebApplicationContext(); webApplicationContext.register(ApplicationConfig.class, WebMvcConfig.class); Dynamic dynamc = servletContext.addServlet("dispatcherServlet", new DispatcherServlet(webApplicationContext)); dynamc.addMapping("/api/v1/*"); dynamc.setLoadOnStartup(1); } }第六步 創(chuàng)建 Story domain類(lèi)
本應(yīng)用中,我們只有一個(gè)Story domain類(lèi)。
@Document(collection = "stories") public class Story { @Id private String id; private String title; private String text; private String url; private String fullname; private final Date submittedOn = new Date(); private String image; public Story() { } // 為了行文簡(jiǎn)潔,移除了Getter和Setter
以上代碼中,值得注意的有兩處:
@Document annotation指明了將在MongoDB中持續(xù)化的domain對(duì)象。stories指明了將在MongoDB中創(chuàng)建的collection名。
@Id標(biāo)記此字段為Id,相應(yīng)的字段會(huì)由MongoDB自動(dòng)生成。
第七步 創(chuàng)建 StoryRepository正如前面所說(shuō),。Spring MongoDB有一個(gè)倉(cāng)庫(kù)概念,你在其中實(shí)現(xiàn)接口,然后Spring會(huì)生成相應(yīng)的代理類(lèi)。讓我們創(chuàng)建如下所示的StoryRepository.
import java.util.List; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; import com.getbookmarks.domain.Story; @Repository public interface StoryRepository extends CrudRepository{ public List findAll(); }
上面的代碼中值得注意的是:
StoryRepository接口擴(kuò)展了CrudRepository接口,CrudRepository接口定義了CRUD、finder方法。因此Spring生成的代理將具備這些方法。
@Repository是一個(gè)特殊的@Component annotation,表明這個(gè)類(lèi)是一個(gè)倉(cāng)庫(kù)或DAO類(lèi)。配合PersistenceExceptionTranslationPostProcessor使用時(shí),有@epository的類(lèi)可以被Spring的DataAccessException轉(zhuǎn)換。
第八步 編寫(xiě)StoryResource接著,我們將編寫(xiě)執(zhí)行創(chuàng)建和讀取報(bào)道操作的REST JSON web服務(wù)。我們創(chuàng)建一個(gè)Spring MVC控制器,包含下面的方法:
@Controller @RequestMapping("/stories") public class StoryResource { private StoryRepository storyRepository; @Autowired public StoryResource(StoryRepository storyRepository) { this.storyRepository = storyRepository; } @RequestMapping(consumes = MediaType.APPLICATION_JSON_VALUE) @ResponseBody public ResponseEntity第九步 配置AngularJS和Twitter BootstrapsubmitStory(@RequestBody Story story) { Story storyWithExtractedInformation = decorateWithInformation(story); storyRepository.save(storyWithExtractedInformation); ResponseEntity responseEntity = new ResponseEntity<>(HttpStatus.CREATED); return responseEntity; } @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody public List allStories() { return storyRepository.findAll(); } @RequestMapping(value = "/{storyId}", produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody public Story showStory(@PathVariable("storyId") String storyId) { Story story = storyRepository.findOne(storyId); if (story == null) { throw new StoryNotFoundException(storyId); } return story; } private Story decorateWithInformation(Story story) { String url = story.getUrl(); RestTemplate restTemplate = new RestTemplate(); ResponseEntity forEntity = restTemplate.getForEntity( "http://gooseextractor-t20.rhcloud.com/api/v1/extract?url=" + url, Story.class); if (forEntity.hasBody()) { return new Story(story, forEntity.getBody()); } return story; } }
從官網(wǎng)下載最新版的AngularJS和Bootstrap?;蛘?,你可以從本項(xiàng)目的github 倉(cāng)庫(kù)復(fù)制過(guò)來(lái)。
第十步 創(chuàng)建 index.html現(xiàn)在我們要編寫(xiě)應(yīng)用的頁(yè)面
GetBookmarks : Submit Story
在以上展示的html代碼中:
我們導(dǎo)入了需要的庫(kù)。我們的應(yīng)用代碼在app.js中。
在Angular中,我們使用ng-app指令定義項(xiàng)目的作用域。在上面的代碼中,我們?cè)趆tml元素中加了ng-app,實(shí)際上我們可以在任何元素中使用。在html元素中使用ng-app指令,意味著AngularJS在整個(gè)index.html中可用。ng-app指令可以指定一個(gè)名稱(chēng)。這個(gè)名稱(chēng)是模塊的名稱(chēng)。我使用getbookmarks作為該應(yīng)用的模塊名。
index.html中使用了ng-view指令。該指令渲染與index.html中的路由相應(yīng)的模板。所以,每次你訪問(wèn)一個(gè)路由,只有ng-view區(qū)域發(fā)生改變。
第十一步 編寫(xiě)AngularJS代碼app.js中包含所有的應(yīng)用相關(guān)代碼。定義了所有的應(yīng)用路由。在以下代碼中,我們將定義三個(gè)路由,以及相應(yīng)的Angular控制器。
angular.module("getbookmarks.services", ["ngResource"]). factory("Story", function ($resource) { var Story = $resource("/api/v1/stories/:storyId", {storyId: "@id"}); Story.prototype.isNew = function(){ return (typeof(this.id) === "undefined"); } return Story; }); angular.module("getbookmarks", ["getbookmarks.services"]). ` config(function ($routeProvider) { $routeProvider .when("/", {templateUrl: "views/stories/list.html", controller: StoryListController}) .when("/stories/new", {templateUrl: "views/stories/create.html", controller: StoryCreateController}) .when("/stories/:storyId", {templateUrl: "views/stories/detail.html", controller: StoryDetailController}); }); function StoryListController($scope, Story) { $scope.stories = Story.query(); } function StoryCreateController($scope, $routeParams, $location, Story) { $scope.story = new Story(); $scope.save = function () { $scope.story.$save(function (story, headers) { toastr.success("Submitted New Story"); $location.path("/"); }); }; } function StoryDetailController($scope, $routeParams, $location, Story) { var storyId = $routeParams.storyId; $scope.story = Story.get({storyId: storyId}); }第十一步 部署代碼
最后,提交代碼,推送到應(yīng)用gear.
git add . git commit -am "application code" git push
這就是今天的內(nèi)容。歡迎反饋。
原文 Day 22: Developing Single Page Applications with Spring, MongoDB, and AngularJS
翻譯 SegmentFault
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/18697.html
摘要:在被收購(gòu)之后,維護(hù)并繼續(xù)發(fā)展。設(shè)置是告訴應(yīng)用在目錄尋找應(yīng)用模板。設(shè)置告訴應(yīng)用使用目錄里面的類(lèi)似圖像文件等靜態(tài)文件。我們會(huì)在應(yīng)用開(kāi)發(fā)過(guò)程中,保持著調(diào)試器在后臺(tái)運(yùn)行。這能提供高效的開(kāi)發(fā)環(huán)境。我們會(huì)把回應(yīng)狀態(tài)設(shè)為已創(chuàng)建。 編者注:我們發(fā)現(xiàn)了有趣的系列文章《30天學(xué)習(xí)30種新技術(shù)》,正在翻譯,一天一篇更新,年終禮包。下面是第23天的內(nèi)容。 今天的《30天學(xué)習(xí)30種新技術(shù)》,我決定暫時(shí)放下...
摘要:指南無(wú)論你正在構(gòu)建什么,這些指南都旨在讓你盡快提高工作效率使用團(tuán)隊(duì)推薦的最新項(xiàng)目版本和技術(shù)。使用進(jìn)行消息傳遞了解如何將用作消息代理。安全架構(gòu)的主題指南,這些位如何組合以及它們?nèi)绾闻c交互。使用的主題指南以及如何為應(yīng)用程序創(chuàng)建容器鏡像。 Spring 指南 無(wú)論你正在構(gòu)建什么,這些指南都旨在讓你盡快提高工作效率 — 使用Spring團(tuán)隊(duì)推薦的最新Spring項(xiàng)目版本和技術(shù)。 入門(mén)指南 這些...
摘要:在我的機(jī)子上,運(yùn)行于端口,以避免和其他默認(rèn)運(yùn)行于端口的沖突。我們可以使用命令連接數(shù)據(jù)庫(kù)查看定義應(yīng)用層次創(chuàng)建的模板應(yīng)用有一個(gè)問(wèn)題,客戶(hù)端和服務(wù)器段的代碼是一樣的。在中加入然后添加問(wèn)題模板注意我們使用了來(lái)確保用戶(hù)未登錄的情況下應(yīng)用。 編者注:我們發(fā)現(xiàn)了有趣的一系列文章《30天學(xué)習(xí)30種新技術(shù)》,正在翻譯中,一天一篇更新,年終禮包。下面是第15天的內(nèi)容。 到目前為止我們討論了Bower...
摘要:在我的機(jī)子上,運(yùn)行于端口,以避免和其他默認(rèn)運(yùn)行于端口的沖突。我們可以使用命令連接數(shù)據(jù)庫(kù)查看定義應(yīng)用層次創(chuàng)建的模板應(yīng)用有一個(gè)問(wèn)題,客戶(hù)端和服務(wù)器段的代碼是一樣的。在中加入然后添加問(wèn)題模板注意我們使用了來(lái)確保用戶(hù)未登錄的情況下應(yīng)用。 編者注:我們發(fā)現(xiàn)了有趣的一系列文章《30天學(xué)習(xí)30種新技術(shù)》,正在翻譯中,一天一篇更新,年終禮包。下面是第15天的內(nèi)容。 到目前為止我們討論了Bower...
摘要:通過(guò)如下命令發(fā)布控制臺(tái),運(yùn)行編寫(xiě)的默認(rèn)程序。默認(rèn)禁用,啟用它需要打開(kāi)并取消注釋以下行。啟用數(shù)據(jù)庫(kù)啟動(dòng)應(yīng)用程序的數(shù)據(jù)庫(kù),框架提供了內(nèi)置的數(shù)據(jù)庫(kù)的支持。當(dāng)用戶(hù)發(fā)出請(qǐng)求到,一個(gè)新的將被創(chuàng)建。方法為給定的獲取,把這個(gè)轉(zhuǎn)換成格式并返回響應(yīng)。 編者注:我們發(fā)現(xiàn)了有趣的系列文章《30天學(xué)習(xí)30種新技術(shù)》,正在翻譯,一天一篇更新,年終禮包。下面是第 30 天的內(nèi)容。 今天是最后一天,我決定學(xué)習(xí)一...
閱讀 872·2023-04-25 16:55
閱讀 2987·2021-10-11 10:59
閱讀 2217·2021-09-09 11:38
閱讀 1905·2021-09-03 10:40
閱讀 1589·2019-08-30 15:52
閱讀 1235·2019-08-30 15:52
閱讀 1058·2019-08-29 15:33
閱讀 3570·2019-08-29 11:26