只是為了學習的話,你可以在這裡本例中使用的模板。 它是一個小型應用程式,這是不符合伺服器互動。所以需要重新整理頁面重新載入資料。
現在讓我們開始!
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.yiibai.springmvc</groupId> <artifactId>Spring4MVCAngularJSExample</artifactId> <packaging>war</packaging> <version>1.0.0</version> <name>Spring4MVCAngularJSExample Maven Webapp</name> <properties> <springframework.version>4.2.0.RELEASE</springframework.version> <jackson.version>2.5.3</jackson.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> </dependencies> <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.4</version> <configuration> <warSourceDirectory>src/main/webapp</warSourceDirectory> <warName>Spring4MVCAngularJSExample</warName> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </pluginManagement> <finalName>Spring4MVCAngularJSExample</finalName> </build> </project>
這裡的應用程式的用戶端是基於AngularJS。如果你想學習AngularJs,那麼不訪看看我們的 AngularJS教學 可讓你在最流行的JavaScript框架有一個了解認識。
模組是AngularJS應用中最重要的部分。AngularJS模組你可以認為是在Java中的包。它應用程式的容器有不同部分 - 控制器,伺服器,過濾器,指令等。AngularJS可以組合某些功能/Javascript在一起在單個模組之下。
模組可用於通過AngularJS來引導應用程式。 通過傳遞模組名到 ng-app 指令,我們可以告訴AngularJS載入該模組的應用程式主入口點。
app.js
'use strict'; var App = angular.module('myApp',[]);
在我們的應用中,將與Spring REST API,例如基於後端伺服器的方式進行通訊。在基於AngularJS應用中,與伺服器進行通訊的首選方式是使用AngularJS內建的 $http 服務。 AngularJS$ http服務允許我們使用XHR[瀏覽器的XMLHttpRequest物件] API與伺服器端點通訊。
user_service.js
'use strict'; App.factory('UserService', ['$http', '$q', function($http, $q){ return { fetchAllUsers: function() { return $http.get('http://localhost:8080/Spring4MVCAngularJSExample/user/') .then( function(response){ return response.data; }, function(errResponse){ console.error('Error while fetching users'); return $q.reject(errResponse); } ); }, createUser: function(user){ return $http.post('http://localhost:8080/Spring4MVCAngularJSExample/user/', user) .then( function(response){ return response.data; }, function(errResponse){ console.error('Error while creating user'); return $q.reject(errResponse); } ); }, updateUser: function(user, id){ return $http.put('http://localhost:8080/Spring4MVCAngularJSExample/user/'+id, user) .then( function(response){ return response.data; }, function(errResponse){ console.error('Error while updating user'); return $q.reject(errResponse); } ); }, deleteUser: function(id){ return $http.delete('http://localhost:8080/Spring4MVCAngularJSExample/user/'+id) .then( function(response){ return response.data; }, function(errResponse){ console.error('Error while deleting user'); return $q.reject(errResponse); } ); } }; }]);
控制器是一個AngularJS應用的最有用的部分。這些是執行JavaScript函式/物件大多數使用者介面相關的工作。它們可以被看作是驅動程式模型和檢視的變化。它們是模型(在我們的應用程式中的資料),和檢視(無論使用者看到在螢幕上以及與其互動)之間的閘道器。
user_controller.js
'use strict'; App.controller('UserController', ['$scope', 'UserService', function($scope, UserService) { var self = this; self.user={id:null,username:'',address:'',email:''}; self.users=[]; self.fetchAllUsers = function(){ UserService.fetchAllUsers() .then( function(d) { self.users = d; }, function(errResponse){ console.error('Error while fetching Currencies'); } ); }; self.createUser = function(user){ UserService.createUser(user) .then( self.fetchAllUsers, function(errResponse){ console.error('Error while creating User.'); } ); }; self.updateUser = function(user, id){ UserService.updateUser(user, id) .then( self.fetchAllUsers, function(errResponse){ console.error('Error while updating User.'); } ); }; self.deleteUser = function(id){ UserService.deleteUser(id) .then( self.fetchAllUsers, function(errResponse){ console.error('Error while deleting User.'); } ); }; self.fetchAllUsers(); self.submit = function() { if(self.user.id===null){ console.log('Saving New User', self.user); self.createUser(self.user); }else{ self.updateUser(self.user, self.user.id); console.log('User updated with id ', self.user.id); } self.reset(); }; self.edit = function(id){ console.log('id to be edited', id); for(var i = 0; i < self.users.length; i++){ if(self.users[i].id === id) { self.user = angular.copy(self.users[i]); break; } } }; self.remove = function(id){ console.log('id to be deleted', id); if(self.user.id === id) {//clean form if the user to be deleted is shown there. self.reset(); } self.deleteUser(id); }; self.reset = function(){ self.user={id:null,username:'',address:'',email:''}; $scope.myForm.$setPristine(); //reset Form }; }]);
在這裡,我們在操作上有些傳統,並用純JSP封裝我們上面寫的所有的AngularJS程式碼。請注意,您可以使用其他FE技術,而不是JSP(Velocity模板為例)。我們還增加了bootstrap 以增強其外觀和感覺。此外,我們也將進行必要的表單驗證。
UserManagement.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>AngularJS $http Example</title> <style> .username.ng-valid { background-color: lightgreen; } .username.ng-dirty.ng-invalid-required { background-color: red; } .username.ng-dirty.ng-invalid-minlength { background-color: yellow; } .email.ng-valid { background-color: lightgreen; } .email.ng-dirty.ng-invalid-required { background-color: red; } .email.ng-dirty.ng-invalid-email { background-color: yellow; } </style> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> <link href="<c:url value='/static/css/app.css' />" rel="stylesheet"></link> </head> <body ng-app="myApp" class="ng-cloak"> <div class="generic-container" ng-controller="UserController as ctrl"> <div class="panel panel-default"> <div class="panel-heading"><span class="lead">User Registration Form </span></div> <div class="formcontainer"> <form ng-submit="ctrl.submit()" name="myForm" class="form-horizontal"> <input type="hidden" ng-model="ctrl.user.id" /> <div class="row"> <div class="form-group col-md-12"> <label class="col-md-2 control-lable" for="uname">Name</label> <div class="col-md-7"> <input type="text" ng-model="ctrl.user.username" id="uname" class="username form-control input-sm" placeholder="Enter your name" required ng-minlength="3"/> <div class="has-error" ng-show="myForm.$dirty"> <span ng-show="myForm.uname.$error.required">This is a required field</span> <span ng-show="myForm.uname.$error.minlength">Minimum length required is 3</span> <span ng-show="myForm.uname.$invalid">This field is invalid </span> </div> </div> </div> </div> <div class="row"> <div class="form-group col-md-12"> <label class="col-md-2 control-lable" for="address">Address</label> <div class="col-md-7"> <input type="text" ng-model="ctrl.user.address" id="address" class="form-control input-sm" placeholder="Enter your Address. [This field is validation free]"/> </div> </div> </div> <div class="row"> <div class="form-group col-md-12"> <label class="col-md-2 control-lable" for="email">Email</label> <div class="col-md-7"> <input type="email" ng-model="ctrl.user.email" id="email" class="email form-control input-sm" placeholder="Enter your Email" required/> <div class="has-error" ng-show="myForm.$dirty"> <span ng-show="myForm.email.$error.required">This is a required field</span> <span ng-show="myForm.email.$invalid">This field is invalid </span> </div> </div> </div> </div> <div class="row"> <div class="form-actions floatRight"> <input type="submit" value="{{!ctrl.user.id ? 'Add' : 'Update'}}" class="btn btn-primary btn-sm" ng-disabled="myForm.$invalid"> <button type="button" ng-click="ctrl.reset()" class="btn btn-warning btn-sm" ng-disabled="myForm.$pristine">Reset Form</button> </div> </div> </form> </div> </div> <div class="panel panel-default"> <!-- Default panel contents --> <div class="panel-heading"><span class="lead">List of Users </span></div> <div class="tablecontainer"> <table class="table table-hover"> <thead> <tr> <th>ID.</th> <th>Name</th> <th>Address</th> <th>Email</th> <th width="20%"></th> </tr> </thead> <tbody> <tr ng-repeat="u in ctrl.users"> <td><span ng-bind="u.id"></span></td> <td><span ng-bind="u.username"></span></td> <td><span ng-bind="u.address"></span></td> <td><span ng-bind="u.email"></span></td> <td> <button type="button" ng-click="ctrl.edit(u.id)" class="btn btn-success custom-width">Edit</button> <button type="button" ng-click="ctrl.remove(u.id)" class="btn btn-danger custom-width">Remove</button> </td> </tr> </tbody> </table> </div> </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js"></script> <script src="<c:url value='/static/js/app.js' />"></script> <script src="<c:url value='/static/js/service/user_service.js' />"></script> <script src="<c:url value='/static/js/controller/user_controller.js' />"></script> </body> </html>
下面顯示的是一個基於REST控制器。這相同於 Spring MVC中4 RESTful Web服務的CRUD例子+RestTemplate中的控制器。唯一的區別在於使用者[模型物件]具有不同的特性,這是根據在本範例的使用者介面。
package com.yiibai.springmvc.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.util.UriComponentsBuilder; import com.yiibai.springmvc.model.User; import com.yiibai.springmvc.service.UserService; @RestController public class HelloWorldRestController { @Autowired UserService userService; //Service which will do all data retrieval/manipulation work //-------------------Retrieve All Users-------------------------------------------------------- @RequestMapping(value = "/user/", method = RequestMethod.GET) public ResponseEntity<List<User>> listAllUsers() { List<User> users = userService.findAllUsers(); if(users.isEmpty()){ return new ResponseEntity<List<User>>(HttpStatus.NO_CONTENT);//You many decide to return HttpStatus.NOT_FOUND } return new ResponseEntity<List<User>>(users, HttpStatus.OK); } //-------------------Retrieve Single User-------------------------------------------------------- @RequestMapping(value = "/user/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<User> getUser(@PathVariable("id") long id) { System.out.println("Fetching User with id " + id); User user = userService.findById(id); if (user == null) { System.out.println("User with id " + id + " not found"); return new ResponseEntity<User>(HttpStatus.NOT_FOUND); } return new ResponseEntity<User>(user, HttpStatus.OK); } //-------------------Create a User-------------------------------------------------------- @RequestMapping(value = "/user/", method = RequestMethod.POST) public ResponseEntity<Void> createUser(@RequestBody User user, UriComponentsBuilder ucBuilder) { System.out.println("Creating User " + user.getUsername()); if (userService.isUserExist(user)) { System.out.println("A User with name " + user.getUsername() + " already exist"); return new ResponseEntity<Void>(HttpStatus.CONFLICT); } userService.saveUser(user); HttpHeaders headers = new HttpHeaders(); headers.setLocation(ucBuilder.path("/user/{id}").buildAndExpand(user.getId()).toUri()); return new ResponseEntity<Void>(headers, HttpStatus.CREATED); } //------------------- Update a User -------------------------------------------------------- @RequestMapping(value = "/user/{id}", method = RequestMethod.PUT) public ResponseEntity<User> updateUser(@PathVariable("id") long id, @RequestBody User user) { System.out.println("Updating User " + id); User currentUser = userService.findById(id); if (currentUser==null) { System.out.println("User with id " + id + " not found"); return new ResponseEntity<User>(HttpStatus.NOT_FOUND); } currentUser.setUsername(user.getUsername()); currentUser.setAddress(user.getAddress()); currentUser.setEmail(user.getEmail()); userService.updateUser(currentUser); return new ResponseEntity<User>(currentUser, HttpStatus.OK); } //------------------- Delete a User -------------------------------------------------------- @RequestMapping(value = "/user/{id}", method = RequestMethod.DELETE) public ResponseEntity<User> deleteUser(@PathVariable("id") long id) { System.out.println("Fetching & Deleting User with id " + id); User user = userService.findById(id); if (user == null) { System.out.println("Unable to delete. User with id " + id + " not found"); return new ResponseEntity<User>(HttpStatus.NOT_FOUND); } userService.deleteUserById(id); return new ResponseEntity<User>(HttpStatus.NO_CONTENT); } //------------------- Delete All Users -------------------------------------------------------- @RequestMapping(value = "/user/", method = RequestMethod.DELETE) public ResponseEntity<User> deleteAllUsers() { System.out.println("Deleting All Users"); userService.deleteAllUsers(); return new ResponseEntity<User>(HttpStatus.NO_CONTENT); } }
package com.yiibai.springmvc.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller @RequestMapping("/") public class IndexController { @RequestMapping(method = RequestMethod.GET) public String getIndexPage() { return "UserManagement"; } }
package com.yiibai.springmvc.service; import java.util.List; import com.yiibai.springmvc.model.User; public interface UserService { User findById(long id); User findByName(String name); void saveUser(User user); void updateUser(User user); void deleteUserById(long id); List<User> findAllUsers(); void deleteAllUsers(); public boolean isUserExist(User user); }
package com.yiibai.springmvc.service; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.concurrent.atomic.AtomicLong; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.yiibai.springmvc.model.User; @Service("userService") @Transactional public class UserServiceImpl implements UserService{ private static final AtomicLong counter = new AtomicLong(); private static List<User> users; static{ users= populateDummyUsers(); } public List<User> findAllUsers() { return users; } public User findById(long id) { for(User user : users){ if(user.getId() == id){ return user; } } return null; } public User findByName(String name) { for(User user : users){ if(user.getUsername().equalsIgnoreCase(name)){ return user; } } return null; } public void saveUser(User user) { user.setId(counter.incrementAndGet()); users.add(user); } public void updateUser(User user) { int index = users.indexOf(user); users.set(index, user); } public void deleteUserById(long id) { for (Iterator<User> iterator = users.iterator(); iterator.hasNext(); ) { User user = iterator.next(); if (user.getId() == id) { iterator.remove(); } } } public boolean isUserExist(User user) { return findByName(user.getUsername())!=null; } public void deleteAllUsers(){ users.clear(); } private static List<User> populateDummyUsers(){ List<User> users = new ArrayList<User>(); users.add(new User(counter.incrementAndGet(),"Sam", "NY", "[email protected]")); users.add(new User(counter.incrementAndGet(),"Tomy", "ALBAMA", "[email protected]")); users.add(new User(counter.incrementAndGet(),"Kelly", "NEBRASKA", "[email protected]")); return users; } }
package com.yiibai.springmvc.model; public class User { private long id; private String username; private String address; private String email; public User(){ id=0; } public User(long id, String username, String address, String email){ this.id = id; this.username = username; this.address = address; this.email = email; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (int) (id ^ (id >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof User)) return false; User other = (User) obj; if (id != other.id) return false; return true; } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", address=" + address + ", email=" + email + "]"; } }
package com.yiibai.springmvc.configuration; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.JstlView; @Configuration @EnableWebMvc @ComponentScan(basePackages = "com.yiibai.springmvc") public class HelloWorldConfiguration extends WebMvcConfigurerAdapter{ @Override public void configureViewResolvers(ViewResolverRegistry registry) { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setViewClass(JstlView.class); viewResolver.setPrefix("/WEB-INF/views/"); viewResolver.setSuffix(".jsp"); registry.viewResolver(viewResolver); } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**").addResourceLocations("/static/"); } }
package com.yiibai.springmvc.configuration; import javax.servlet.Filter; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class HelloWorldInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[] { HelloWorldConfiguration.class }; } @Override protected Class<?>[] getServletConfigClasses() { return null; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } @Override protected Filter[] getServletFilters() { Filter [] singleton = { new CORSFilter() }; return singleton; } }
package com.yiibai.springmvc.configuration; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletResponse; public class CORSFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { System.out.println("Filtering on..........................................................."); HttpServletResponse response = (HttpServletResponse) res; response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type"); chain.doFilter(req, res); } public void init(FilterConfig filterConfig) {} public void destroy() {} }
現在構建war(無論是在Eclipse中,如提到的前面的教學)或通過Maven的命令列(mvn clean install)。部署 war 到Servlet3.0容器。
開啟瀏覽器,瀏覽:http://localhost:8080/Spring4MVCAngularJSExample/
由於AngularJS表單驗證,如果試圖不按要求提供輸入,你會看到驗證錯誤如下圖所示。
就這樣(包教不包會)!