SpringMVC + Angularjs
来源:互联网 发布:android水印相机源码 编辑:程序博客网 时间:2024/05/02 18:43
本博客将展示使用AngularJS和Spring MVC4,我们将创建一个增删查改的应用。前端使用AngularJS,后端使用Spring REST API。AngularJS使用$http服务和后端进行异步通信,同时使用AngularJS进行表单验证。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
在本应用中,客户端是基于AngularJS,服务器端基于Spring REST API。最终本应用界面如下:
功能展示:
只是为了展示后台使用模拟数据,你也可以进一步扩展程序使所有的数据都保存到数据库中。
让我们开始本应用开发。
所涉及到的技术点为:
- Spring 4.3.1.RELEASE
- AngularJS 1.4.4
- Maven 3
- JDK 1.7
- Eclipse JUNO Service Release 2
- M2Eclipse plugin (Optional)
maven依赖库如下:
<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.websystique.springmvc</groupId> <artifactId>Spring4MVCAngularJSExample</artifactId> <packaging>war</packaging> <version>1.0.0</version> <name>Spring4MVCAngularJSExample Maven Webapp</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <springframework.version>4.3.1.RELEASE</springframework.version> <jackson.version>2.7.5</jackson.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</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> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.2</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> <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> <finalName>Spring4MVCAngularJSExample</finalName> </build></project>
1,前端部分
本应用前端是基于angularjs框架的。如果你想增加angularJS的开发水平建议把angularJS官方文档学习一遍,AngularJS是比较流行的前端框架。
创建AngularJS模块
模块是AngularJS应用中最重要的一部分,一个模块可被认为是java中的一个包。模块中可以包含应用的各个部分,控制器,服务,过滤器,指令等。
模块可以被用于AngularJS作为整个程序启动程序。通过增加ng-model这个指令我们能告诉AngularJS从哪里开始作为应用的入口程序。如下是我们定义的模块。想要了解AngularJS模块相关的概念,请阅读官方文档。
app.js
'use strict'; var App = angular.module('myApp',[]);
创建AngularJS服务与服务器进行通信
在我们的应用中,我们将和Spring REST API后台进行通信,前端部分我们将使用AngularJS内建的$http服务。AngularJS 的$http服务封装了XHR对象方便我们
与服务器进行数据交互。$http是基于promise对象传递异步消息。本应用的service如下:
user_service.js
'use strict'; angular.module('myApp').factory('UserService', ['$http', '$q', function($http, $q){ var REST_SERVICE_URI = 'http://localhost:8080/Spring4MVCAngularJSExample/user/'; var factory = { fetchAllUsers: fetchAllUsers, createUser: createUser, updateUser:updateUser, deleteUser:deleteUser }; return factory; function fetchAllUsers() { var deferred = $q.defer(); $http.get(REST_SERVICE_URI) .then( function (response) { deferred.resolve(response.data); }, function(errResponse){ console.error('Error while fetching Users'); deferred.reject(errResponse); } ); return deferred.promise; } function createUser(user) { var deferred = $q.defer(); $http.post(REST_SERVICE_URI, user) .then( function (response) { deferred.resolve(response.data); }, function(errResponse){ console.error('Error while creating User'); deferred.reject(errResponse); } ); return deferred.promise; } function updateUser(user, id) { var deferred = $q.defer(); $http.put(REST_SERVICE_URI+id, user) .then( function (response) { deferred.resolve(response.data); }, function(errResponse){ console.error('Error while updating User'); deferred.reject(errResponse); } ); return deferred.promise; } function deleteUser(id) { var deferred = $q.defer(); $http.delete(REST_SERVICE_URI+id) .then( function (response) { deferred.resolve(response.data); }, function(errResponse){ console.error('Error while deleting User'); deferred.reject(errResponse); } ); return deferred.promise; } }]);
请注意如上url部分的硬编码 [http://localhost:8080/],在发布的时候要根据具体的主机/端口号进行调整。
创建AngularJS控制器
控制器是AngularJS应用中最有用的部分,UI中大多数的操作都需要在controller中进行逻辑控制,可被认为是模型和视图改变的驱动程序。是模型和视图之间的网关。控制器主要的职责是为UI提供数据,数据可以是静态的也可以是来自服务器端的,管理展示逻辑,例如什么元素该显示什么元素该隐藏,需要用什么主题等。处理用户输入,例如当用户点击某一控件是会发生什么,输入的数据是否是有效的,处理用户的数据并发给服务器。
user_controller.js
'use strict'; angular.module('myApp').controller('UserController', ['$scope', 'UserService', function($scope, UserService) { var self = this; self.user={id:null,username:'',address:'',email:''}; self.users=[]; self.submit = submit; self.edit = edit; self.remove = remove; self.reset = reset; fetchAllUsers(); function fetchAllUsers(){ UserService.fetchAllUsers() .then( function(d) { self.users = d; }, function(errResponse){ console.error('Error while fetching Users'); } ); } function createUser(user){ UserService.createUser(user) .then( fetchAllUsers, function(errResponse){ console.error('Error while creating User'); } ); } function updateUser(user, id){ UserService.updateUser(user, id) .then( fetchAllUsers, function(errResponse){ console.error('Error while updating User'); } ); } function deleteUser(id){ UserService.deleteUser(id) .then( fetchAllUsers, function(errResponse){ console.error('Error while deleting User'); } ); } function submit() { if(self.user.id===null){ console.log('Saving New User', self.user); createUser(self.user); }else{ updateUser(self.user, self.user.id); console.log('User updated with id ', self.user.id); } reset(); } function edit(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; } } } function remove(id){ console.log('id to be deleted', id); if(self.user.id === id) {//clean form if the user to be deleted is shown there. reset(); } deleteUser(id); } function reset(){ self.user={id:null,username:'',address:'',email:''}; $scope.myForm.$setPristine(); //reset Form } }]);
为Spring MVC应用创建视图
本应用我们展示传统的方式完成视图创建,使用JSP封装AngularJS的方式。你也可以创建纯html文件,为了界面美观我们添加了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>
2,服务器端
使用Spring MVC创建REST应用,代码如下:
package com.websystique.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.websystique.springmvc.model.User;import com.websystique.springmvc.service.UserService; @RestControllerpublic 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); } }
创建程序的根controller
如下为程序的根目录对应的controller
package com.websystique.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"; } }
创建Spring Service处理用户提交的数据。
package com.websystique.springmvc.service; import java.util.List; import com.websystique.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.websystique.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 com.websystique.springmvc.model.User; @Service("userService")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", "sam@abc.com")); users.add(new User(counter.incrementAndGet(),"Tomy", "ALBAMA", "tomy@abc.com")); users.add(new User(counter.incrementAndGet(),"Kelly", "NEBRASKA", "kelly@abc.com")); return users; } }
创建模型
package com.websystique.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 + "]"; } }
创建Spring配置文件
package com.websystique.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.websystique.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/"); } }
创建Spring初始化类
看如下代码是如何配置CORS过滤的,帮助我们处理同源策略问题。
package com.websystique.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.websystique.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包或者通过maven命令打包程序,发布war到Servlet3.0容器中,本次开发使用的Tomcat,仅仅需要将war包放到tomcat的webapps目录
下,点击startup.bat即可启动服务器。
打开浏览器并输入http://localhost:8080/Spring4MVCAngularJSExample/将能看到如下界面:
新增用户:
点击新增后,用户信息将会异步发送到服务器并新增一条记录
点击删除后,用户信息将被删除
点击编辑后用户信息将会显示到表单中方便更新。还有部分功能就不演示了。
项目代码: https://github.com/yuanlunchuan/spring4Angular
csdn下载地址:http://download.csdn.net/detail/u010381707/9677924
- SpringMVC + Angularjs
- Solr+AngularJS+springMVC+搜索
- 【AngularJS】AngularJS整合Springmvc、Mybatis环境搭建
- SpringMVC实现angularjs图片上传
- springmvc + angularjs 跨域问题解决
- SpringMvc+Angularjs 多文件批量上传
- AngularJs与SpringMVC简单结合使用
- angularjs 与 springmvc 遇到的一些问题
- springmvc和Angularjs 跨域传输 jsonp
- 使用SpringMVC+Angularjs实现登录功能
- AngularJS SpringMVC解决post参数获取失败
- AngularJs与SpringMVC简单结合使用
- spring+springmvc+mybatis+angularjs java web项目
- SpringMvc+AngularJS通过CORS实现跨域方案
- bootstrap + angularjs + springmvc + mybatis框架之图片上传和展示
- bootstrap + angularjs + springmvc + mybatis框架之加载log4j日志
- 【js类库AngularJs】解决angular+springmvc的post提交问题
- SpringMvc互联AngularJS通过代码拦截实现跨域方案
- dwr的介绍和实例
- 一天一条Linux指令-killall
- 详解.htm.html.shtm.shtml的区别与联系
- 对系统圆形进度条的改进,使首尾圆滑接触
- 【教程】Raspberry PI 树莓派使用XBMC的五种方式
- SpringMVC + Angularjs
- 2016最新前端学习计划
- mysql跳过密码登录
- Caused by: java.lang.IllegalStateException: package not installed?
- FunGameRefresh 下拉刷新库
- 实验任务7 实现登录界面的账号和密码的存储功能
- 一天一条Linux指令-whereis
- OpenCart 最新使用教学视频合集
- Mysql设置允许外网访问