SpringMVC+Angularjs

SpringMVC+Angularjs,本文將展示使用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依賴庫如下:

    
        4.0.0
        com.websystique.springmvc
        Spring4MVCAngularJSExample
        war
        1.0.0
        Spring4MVCAngularJSExample Maven Webapp
     
        
            UTF-8
            4.3.1.RELEASE
            2.7.5
        
     
        
            
                org.springframework
                spring-webmvc
                ${springframework.version}
            
            
                com.fasterxml.jackson.core
                jackson-databind
                ${jackson.version}
            
            
                javax.servlet
                javax.servlet-api
                3.1.0
            
            
                javax.servlet
                jstl
                1.2
            
        
     
     
        
            
                
                    org.apache.maven.plugins
                    maven-compiler-plugin
                    3.2
                    
                        1.7
                        1.7
                    
                
                
                    org.apache.maven.plugins
                    maven-war-plugin
                    2.4
                    
                        src/main/webapp
                        Spring4MVCAngularJSExample
                        false
                    
                
            
            Spring4MVCAngularJSExample
        
    

    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" %>
    

    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;
      
    @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> listAllUsers() {
            List users = userService.findAllUsers();
            if(users.isEmpty()){
                return new ResponseEntity<list>(HttpStatus.NO_CONTENT);//You many decide to return HttpStatus.NOT_FOUND
            }
            return new ResponseEntity<list>(users, HttpStatus.OK);
        }
      
      
         
        //-------------------Retrieve Single User--------------------------------------------------------
          
        @RequestMapping(value = "/user/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
        public ResponseEntity 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(HttpStatus.NOT_FOUND);
            }
            return new ResponseEntity(user, HttpStatus.OK);
        }
      
          
          
        //-------------------Create a User--------------------------------------------------------
          
        @RequestMapping(value = "/user/", method = RequestMethod.POST)
        public ResponseEntity 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(HttpStatus.CONFLICT);
            }
      
            userService.saveUser(user);
      
            HttpHeaders headers = new HttpHeaders();
            headers.setLocation(ucBuilder.path("/user/{id}").buildAndExpand(user.getId()).toUri());
            return new ResponseEntity(headers, HttpStatus.CREATED);
        }
      
         
          
        //------------------- Update a User --------------------------------------------------------
          
        @RequestMapping(value = "/user/{id}", method = RequestMethod.PUT)
        public ResponseEntity 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(HttpStatus.NOT_FOUND);
            }
      
            currentUser.setUsername(user.getUsername());
            currentUser.setAddress(user.getAddress());
            currentUser.setEmail(user.getEmail());
              
            userService.updateUser(currentUser);
            return new ResponseEntity(currentUser, HttpStatus.OK);
        }
      
         
         
        //------------------- Delete a User --------------------------------------------------------
          
        @RequestMapping(value = "/user/{id}", method = RequestMethod.DELETE)
        public ResponseEntity 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(HttpStatus.NOT_FOUND);
            }
      
            userService.deleteUserById(id);
            return new ResponseEntity(HttpStatus.NO_CONTENT);
        }
      
          
         
        //------------------- Delete All Users --------------------------------------------------------
          
        @RequestMapping(value = "/user/", method = RequestMethod.DELETE)
        public ResponseEntity deleteAllUsers() {
            System.out.println("Deleting All Users");
      
            userService.deleteAllUsers();
            return new ResponseEntity(HttpStatus.NO_CONTENT);
        }
      
    }</list</list</list

    創建程序的根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 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 users;
         
        static{
            users= populateDummyUsers();
        }
     
        public List 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 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 populateDummyUsers(){
            List users = new ArrayList();
            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/將能看到如下界面:

    新增用戶:

    點擊新增後,用戶信息將會異步發送到服務器並新增一條記錄

    點擊刪除後,用戶信息將被刪除

    點擊編輯後用戶信息將會顯示到表單中方便更新。還有部分功能就不演示瞭。

發佈留言