学习(Java Web)编程技术要点及方向; 完成项目的要决

本文亮点:

  • 传统学习编程技术落后,应跟著潮流,要对业务聚焦处理。
  • 要Jar, 不要War;以小为主,以简为宝,集堆而成。
  • 去繁取简 Spring Boot,明日之春。
  • 集堆综合技术如 jHipster 是必然的软件开发途径
  • 前后端分离技术,跨域资源共享( CORS)。
  • 提供Spring Boot 1.3.6 + Angular1.4.0  UI-Route 0.40 + Mongodb 2.6.3 CRUD学习程式例子。

开场白

  一般大专的软件技术课程是这样的,有系统地介绍一下有关该技术的背景,然后概括地描述编程语言的定义, 指令的用法及几个运用的例子,跟著就要做几个技术合量不同的学习顶目。我参考过澳洲某大学的课程,基本上都是这样的。无可非议,这是正统的学习方法!可惜,这种方法偏向教条主义,形式工夫而已,学生学不到真正应用知识的。之所以,几位电脑及互联网著名大亨如比尔·盖茨(Bill Gates,史蒂夫·乔布斯(Steve Jobs)和马克·扎克伯格(Mark Zuckerberg)一样,盖茨等也是从大学辍学而另创途径去学习技术的。笔者注:偏向学术的学位同样重要,盖茨后来都十分认同。 

  事实上,大专学校有关普通电脑技术方面通常是3至5年落后于市场应用,更不用说日新月异的编程技术。当然可以去技术培训学校去学习的。不过, 笔者认为那些所谓技术培训课程形式上和大专的也是差不了多少,更新了部份技术,祇是著重于操作例子多些吧。 

编程方面要提高对业务聚焦处理

  我相信,大部分的计算机程式员/电脑工程师都是从工作中得到应用知识的。笔者在电讯公司任职了两年,再在美国通用电气公司工作时,主管对笔者说:“ 你可能在三年内都不知道你在做些什么,三年以后才真正对我有点用处“。意思是要你学习业务知识三年后才有用。在工作应用方面,知道了一点语言知识远远不够用的! 不少公司招聘电脑程式员/电脑工程师都希望有些经验的,不光是看其技术方面,更重要是业务应用方面,就是这样道理吧。可见,编程技术不过是一种工具, 重点还是应用业务了得!

  行业专家早已洞悉业务的重要性,在编程方面提高了对业务聚焦处理。 不过一般程式员还不清楚怎样在编译中采取主动的步伐,没有在业务应用方向多下功夫,仍然卡在技术层次上落阶梯上。 在笔者朋友中,不少是编程专家和精英,熟练多种语言技术。其中一位编程技术超凡,工作了二十多年,做了不少项目,但是每个项目都是拖延超时,没有按时间表完成的。其道理很简单,项目应以业务为主导的,编程技术祇是工具;必须采取适应的编程技术,集中地处理好业务上的逻辑,这才是项目工作方向。 简易直说就是要花多些时间在业务上,多和客户打交道。笔者曾经在道琼斯的华尔街日报处理网站技术,用了三个月的时间就完成了六个月时间表的项目。深得处理业务的重要性。 

Java 编译技术内容丰富,各种分类技术繁多,又是议论多多的普及技术

  上文花了不少文字来解释业务在编程技术上的份量,那么在学习和应用编程技术方面该怎样进行呢?不管Java, Php, C, C++,虽然他们的语言句法要求不同, 编译中使用的编译工具包不同, 但是其过程和结果都是差不多的。 以下就以 Java 编译技术为主题,它的内容丰富,各种分类技术繁多,又是议论多多的普及技术。 

  Java 是很通用普及的编译语言, 可以在不同的作业系统上运行。有关详细Java 技术, 不是本文讨论议题。本文祇集中在广泛应用的Java Web 技术方面。假设你刚刚从有关电脑技术专科或本科毕业了(软件系统/网页开发),面对你通常有三条路选择: 找到了工作;寻觅工作;再进一步深造。深造当然指出国或考科研。刚出校门,不管你是否有工作,怎么样能够学习新知识,充实自己是首要的任务!其实,可以一面工作一面学习是最隹的搭档,但是对于刚来社会的菜乌,应付工作相信会有不少压力的。此时,不少人就会想到的是可以上网,搜集资料,问百度! 

互联网五花八门,什么都有,简直是中国人所谓的江湖

  现在是互联网世界,网上什么都有,不少人士都能从网上学习了不少的技术及方法。也许你都有过相当次数的经验,可是花了不少时间去寻找一些答案, 总是有点不合使用,问非所答,不是实际情况。那么,应该怎么样学习电脑技术呢?或者怎么样利用网上知识来帮助你解决问题呢?事实上,互联网是人类最大的资料库,包罗万象,你没有想到的都有,问题是你怎样在这洪荒海量的资讯里提走一点对你有用的资料。 更可怕的是不要陷入了一些所谓专家答案的Merry-go-round - 旋转木马圈套里,永远得不到答案的。怎样利用互联网海量的资讯呢?在大同的环境内要采取战略方针:根据具体存在的条件要求寻找方向,该方向是现今流行的编程技术,而不是你马上可以应用具体的方向。这里所说不是专门解答你工作上或者作业上的难题,而是在互联网世界里可以得到学习电脑技术知识的方向,这是十分重要的!举个简单易明的例子,如果你仍然使用Windows XP来处理或开发工作,别人已经在利用Windows 10, 8 等工作了;你完全是Out 了!

  现今科技世界日新月异,大部分是与电脑计算机技术有关的。有作为的公司及机构一定会跟随大方向走的, 不论是经济,产品,尤其是在技术方面的趁势,有时身不由己。前面几段说话有点偏离了学习(Java Web)编程技术要点及方向,不过笔者相信编程技术必须跟随著电脑计算机技术主流的。

编程技术潮流:以小为主,以简为宝,集堆而成

  最新Java软件开发技术是以分离技术为方向, 偏向细小程式。 尤其是要Jar, 不要War! 记得初学Java Web (IEEE),肯定不是轻量级别,十分繁琐。自从有了三剑客出现(Spring, Structs, Hibenate), 编程开发工作的确简化了不少。但是基本还是以XML 编译为核心。社会的生产和工作日益进步,对软件技术有更高的要求, 使用XML 编译的方式已经应付不来,加上容易人为错误,不少新颖的开发技术减轻了对XML的依赖,或减至其使用率为最极限度, 而采用了程式,资料库,新技术如NOSQL,大数据,云操作等处理软件开发技术的新潮流。 

去繁取简又是一个显著的标志

  著名的例子正是 Spring Boot, 包容了一切可应用的启动功能, 包括了所有的annotation 的接口。 Spring 框架的常见问题就是要快速创建一个可以马上运行的应用比较麻烦,学习曲线高!而Spring Boot 可以自动配置 Spring 的各种组件,并不用依赖代码生成和 XML 配置文件。 Spring Boot 可以大大提升使用 Spring 框架时的开发效率。 除了能提供不少自动又高效率的智能装置之外,又是现今可以投入微服务(Microservice)的平台。 Spring Boot被认为future of Spring! 笔者相信它将会取缔其他大部分Spring框架配件。以后可能没有SpringMVC 6, 7续号了。另外一个值得注意的讯息就是常用的Jsp:它和Java同期产物,但Java已是进入第八代了,而Jsp变化不多,加上Jsp不能在嵌套在Tomcat容器来解析,换句话就是不能在打包而成为可执行的Jar情况下解析的。同样地,Jetty嵌套容器也不支持Jsp , 所以Spring Boot 官方不推荐使用Jsp技术。Jsp 也该退休了,祇是时间问题吧。

  现在有规模的项目主流设计一般会采用微服务架构(Microservice Architecture)。简单来说,把所有业务逻辑分析成每个独立性又细少的服务应用,单独部署和开发,分布式的管理,实现了敏捷开发和部署。这就是以小为主的完美。可以应用微服务架构的项目多指有100个开发程式员以上。 

MVC设计典范:Spring Boot

  事实上,软件架构分离技术如MVC设计典范,即是模型(model)-视图(view)-控制器(controller)的分离组织;把业务逻辑、数据、界面显示用分离的方法来组织代码,将业务逻辑集中到一个部件里面,在修正或改进显示结果在界面上,而在用户互动时也不需要重新编写业务逻辑。 MVC用于映射传统的输入、处理和输出功能,而变成在一个逻辑的图形化的结构。 一般软件系统可分前端和后台:后台提供资料数据给前端的; 前端则和用户互动及显示结果的。上文提到的Spring Boot 能够以MVC模型来处理该程式的后台数据资料。 

前端分离模式:AngularJS

  如果前端要采用MVC模型来处理运作的话,那么可以使用 AngularJS。严格来说它是 MVVM (Model-View-ViewModel),当然还有其他, 例如Avalon,Regular,Knockout,都是走的差不多路线的,用类似模板的语法来描述界面状态与数据的绑定关系,当界面发生变化的时候,会按照配置规则去更新相应的数据,或者从数据来更新界面状态。其分离方法原则上都是把状态,数据及视图变成MVC模板处理。注:游戏,图形界面编辑器,这种DOM操作很频繁不适使用 AngularJS。以目前的潮流来说,当然是以 AngularJS + UI-Route用户最多,根据业界的统计。 

集堆综合技术:必然的软件开发途径

  另外一股不容忽视的潮流正是在 Java 平台上利用多种开放源码工具组合而成的集堆综合技术。 比较著名的有 AppFuse 和 jHipster 。简单地说,它们都是能够提供一个项目骨架,来帮助程式员快速地而能高效地开发 Web 应用程序。它可以生成代码,编译,连接资料库和部署,并提供了目录和包结构,以及开发基于 Java 语言的 Web 应用程序所需要的Jar库。上文提及的聚焦在处理好业务上的逻辑,就必须仔细地考虑怎样利用集堆综合技术的应用。 尤其要迎合领导上的项目时间表的规范! 注: AppFuse 3.5 可能是最后一期的更新,明年开始将不会在网上有支援服务了。原因是 AppFuse 的主要创作者 Matt Raible 转向开发及支援他的竞争者 – jHipster. 他表示 jHipster 功能及稳定性都比 AppFuse 强,最重要 是jHipster 能够支持 Java 8, 而 AppFuse 不能。笔者也曾尝试采用过 AppFuse, 的确是不错的 Java Web开发工具组合。现今可以说, jHipster 是一只领头羊。有关 jHipster 的应用,请参考笔者所撰写的慱客分享。

开发及云部署先锋: Docker

  另一类热潮相信非 Docker 莫属。它是一个虚拟容器,像沙箱式的运作。程式祇能在该容器内进行有关的运行,但能分享作业系统的资源。以往程式服务器多在仿真的虚拟硬件内(emulating virtual hardware)操作,现在同样硬件但布置了虚拟容器,就能够支援4至6倍的程式服务器数目。之所以 Docker 又是部署云的工具。它令程序各自各独立工作,又能安全地分享其程式,正是符合典型的可以共同开发系统的结构!正是微服务的好搭档。 

结束语

  本文目的是希望给读者提供一些编程技术方向: 那些是流行的; 这些可能会被淘汰的!故此笔者祇能简单地介绍各种技术的要点。网上有关这些技术资料相信不少,祇是等待有心人去发掘而已。有了大方向,你才可以站得高,望得远!有些读者可能有疑问:大部份的程式员都是在维护系统,这些新技术,新方向有什么作用呀?其实所谓新技术都是和 Java , Spring 有关的。如果系统是按照 MVC 的规范去实践和部署的,例如控制器不会和直接处理业务数据的,那么,该服务流程很容易转移到 Spring Boot 的程式里。或者在 jHipster 程式里,明白其中一些应用程式代码,你可以用同样方法在现在的程式中去处理这些数据的。

 

示范例子

安装和运行汽车搜索及增加修改程式例子需要以下的工作或开发环境:

  • Java 8 SDK
  • Maven 或 Gradle
  • Spring Boot 1.3.6
  • MongoDB
  • AngularJs + UI-Route + Jquery
  • Git 版本控制
  • STS ide, Eclipse, Intellij IDEA, 其中一个

  如果没有一个实用的编程例子,可能有些读者不会认真地体会本文的要点。 笔者就提供一个 Spring Boot + Angular UI-Route + Mongodb CRUD学习程式资料. 笔者要用最简单又有效的编程方法来实践“ 以小为主,以简为宝 ” 的原则。首先什么是小呢?程式可分成前后端分开处理,都是以 MVC 模式安排,加上用跨域资源共享( CORS)来分成前后端的开发。换句话说,前后端各自开发,祇有在程式运作时才有直接数据来往。

后端的开发: Spring Boot + mongoDB + H2

  1. 打开你常用的浏览器, 在 URL 输入https://stat.spring.io
  2. 在页面上输入:

      Maven Project           Spring Boot 1.3.7.

      Group:  com.emo.product

      Artifact: product-server

      Selected Dependencies: Web, MongoDb, H2。

 

图1:自动生成 Spring Boot 骨架项目

 

   然后按一下 Generate Project 按钮,就是自动下载一个压缩 zip 档案,即是 product-server.zip。把该 zip 档案放在适当位置,再解压。在解压后的目录里有 src, .setting, .mvn 及 POM.xml. 打开 pom.xml 会见到这里祇用了3个依赖包 (Web, MongoDb, H2)而已,而其他 Jar 包会自动下载的。该网页 (SPRING INITIALIZR) 就是能够提供 Spring Boot 的项目骨架,最重要的 POM.xml 的程式依赖部署档案。本程式采用了记忆体的资料库 H2, 方便数据资料修改及储存到硬盘上的MonogoDB。

3.     为了容易修改程式文档,当然要输入你所常用的 IDE,例如 Eclipse. 笔者使用的是 STS 3.8.0 RELEASE. 现在你祇有骨架,没有真实的 Java 类,业务,接口等的文档。正是要运用你的 Java 技术了。笔者与人方便,为你提供了汽车搜索及增加修改程式。并附上 MongoDB  资料库档案。 

图2:Product Server Spring Boot项目Java架构

你可以按自己的方式来编制你的Java代码及其有关的类,接口和业务的应用。也可以参考本文的代码。

图3:Product Server Java 所需的程式名称

 

首先是最重要的程式依赖档

Product-server/POM.xml.

<?xml version="1.0" encoding="UTF-8"?>

<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/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.emo.product</groupId>

    <artifactId>product-server</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <packaging>jar</packaging> 

    <name>car-server</name>

    <description>Spring Boot Server</description> 

    <parent>

       <groupId>org.springframework.boot</groupId>

       <artifactId>spring-boot-starter-parent</artifactId>

       <version>1.3.6.RELEASE</version>

       <relativePath/> <!-- lookup parent from repository -->

    </parent>

    <properties>

       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

       <java.version>1.8</java.version>

    </properties>

    <dependencies>

       <dependency>

           <groupId>org.springframework.boot</groupId>

           <artifactId>spring-boot-starter-data-mongodb</artifactId>

       </dependency>

       <dependency>

           <groupId>org.springframework.boot</groupId>

           <artifactId>spring-boot-starter-web</artifactId>

       </dependency>       

       <dependency>

           <groupId>org.springframework.boot</groupId>

           <artifactId>spring-boot-starter-test</artifactId>

           <scope>test</scope>

       </dependency>

    </dependencies>   

    <build>

       <plugins>

           <plugin>

              <groupId>org.springframework.boot</groupId>

              <artifactId>spring-boot-maven-plugin</artifactId>

           </plugin>

       </plugins>

    </build>   

</project>

App.java 典型的Spring Boot 起动程式。

package com.emo.product;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication

@EnableAsync

public class app {   

    public static void main(String[] args) {

       SpringApplication.run(app.class, args);

    }

    public void run() {

    }

}

SimpleCORSFilter.java  跨域资源共享的过滤器

package com.emo.product.config;

 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.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.springframework.http.HttpMethod;

import org.springframework.http.HttpStatus;

import org.springframework.stereotype.Service; 

@Service

public class SimpleCORSFilter implements Filter {   

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {     

       HttpServletResponse response = (HttpServletResponse) res;

       HttpServletRequest request = (HttpServletRequest) req;  

       response.setHeader("Access-Control-Allow-Origin", "*");

       response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");

       response.setHeader("Access-Control-Max-Age", "3600");

       response.setHeader("Access-Control-Allow-Headers", "Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization");

       response.setHeader("Access-Control-Allow-Credentials", "true");

       if(request.getMethod().equals(HttpMethod.OPTIONS.name())){

           response.setStatus(HttpStatus.NO_CONTENT.value());

       }else{

           chain.doFilter(req, res);

       }

    }

    public void init(FilterConfig filterConfig) {}

    public void destroy() {} 

}

CarController.java 汽车控制器,留意程式尽量使用现成的mongoRepository的资料库接口,祇有 update 和 search 才做业务上的运作。因为mongoRepository 没有直接提供现成的接口。少一句代码就简化了一度步骤,减少一个机会犯人为错误的。 

package com.emo.product.controllers;

import java.util.List; 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.ui.Model;

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 com.emo.product.model.Car;

import com.emo.product.repository.CarSearchRepository;

import com.emo.product.repository.CarRepository;

import com.emo.product.service.CarService;

@RestController

@RequestMapping(value="/api")

public class CarController {  

    @Autowired

    CarRepository carRepository; 

    @Autowired

    CarSearchRepository carSearchRepository;  

    @Autowired

    private CarService carService;  

    /**

     * Save car to database

     */

    @RequestMapping(value="/save",method=RequestMethod.POST)

    public String saveCar(@RequestBody Car car) {

       carRepository.save(car);

       return "success";

    } 

    @RequestMapping(value="/getListOfCar",method=RequestMethod.GET)

    public List<Car> getListOfCar() {

       return carRepository.findAll();

    }   

    @RequestMapping("/home")

    public String home(Model model) {

       model.addAttribute("List", carRepository.findAll());

       return "home";

    }   

    @RequestMapping(value="/update",method=RequestMethod.POST)

    public void updateCar(@RequestBody Car car) {

       carService.update(car);

    }   

    @RequestMapping(value = "/search",method=RequestMethod.POST)

    public Car search(@RequestBody String search) {

       Car car = carService.search(search);

       carService.update(car);

       return car;

    }    

    @RequestMapping(value="/delete", method=RequestMethod.POST)

    public void removeCar(@RequestBody Car car) {

       carRepository.delete(car);

    }

}

CarService.java 十分简单的服务

package com.emo.product.service;

import com.emo.product.model.Car;

public interface CarService {

    //update car

    public void update(Car car);   

    //search Car.

    public Car search(String text); 

CarServiceImpl.java 实验服务

package com.emo.product.service;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import com.emo.product.model.Car;

import com.emo.product.repository.CarRepository;

import com.emo.product.repository.CarSearchRepository;

@Service

public class CarServiceImpl implements CarService {  

    @Autowired

    private CarRepository carRegistory;   

    @Autowired

    private CarSearchRepository searchRegistory;  

    @Override

    public  Car search(String text) {

       return searchRegistory.searchCars(text);

    }

    @Override

    public void update(Car car) {

       carRegistory.save(car);

    }

}

CarRepository.java  mongoDB 的接口

package com.emo.product.repository; 

import java.util.List;

import org.springframework.data.mongodb.repository.MongoRepository;

import org.springframework.stereotype.Repository;

import com.emo.product.model.Car;

@Repository

public interface CarRepository extends MongoRepository<Car, String> {

    public List<Car> findAll();

    public Car findOne(String id);

    @SuppressWarnings("unchecked")

    public Car save(Car car);

    public void delete(Car car);

}

 

CarSearchRepository.java 利用mongoTemplate 来查询资料库

package com.emo.product.repository; 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.mongodb.core.MongoTemplate;

import org.springframework.data.mongodb.core.query.Criteria;

import org.springframework.data.mongodb.core.query.Query;

import org.springframework.stereotype.Repository; 

import com.emo.product.model.Car;

@Repository

public class CarSearchRepository {

    @Autowired

    MongoTemplate mongoTemplate;

    public Car searchCars(String text) {

       Car car = mongoTemplate.findOne(Query.query(new Criteria()

                     .orOperator(Criteria.where("description").regex(text, "i"),

                                Criteria.where("make").regex(text, "i"),

                                Criteria.where("model").regex(text, "i"))

                     ), Car.class);

        return car;     

    }

}

application.properties最后是设置mongoDB 的 Host 和 Port.

spring.data.mongodb.database=car_dealer

spring.data.mongodb.host=localhost

spring.data.mongodb.port=27017 

上面就是汽车搜索及增加修改资料程式,十分简洁。不过,Spring Boot 版本 1.4.0在 Windows 10会出错的; 而在 Mac 机上相安无事。读者请留意:本服务程式没有使用 DAO,又没有 JSP ! 制作风险都是与网络顺畅有关的,有时因本机的 jar 包出现问题,要重新下载的,可惜网络不一定给面子, 无奈! 

 

前端的开发: Angular + UI-Route

开始处理所有有关  Java 的程式都是要考虑需要那些依赖包及其版本,AngularJS 也不例外。根据前端程式需要,它多是存在 Bower.json 档的。该档案是记录著该 AngularJS 程序所需要的各类 Jar 包。如果丢失了某个包,可以重新下载的。功能有点像服务程式中的 POM.xml. 

Bower.json 

{

  "name": "angular-auth",

  "version": "0.1",

  "authors": [

    "sam8881"

  ],

  "moduleType": [

    "amd"

  ],

  "license": "MIT",

  "dependencies": {

    "angular-ui-router": "~0.2.15",

    "angular-ui": "~0.4.0",

    "angular": "~1.4.0",

    "jQuery": "~2.1.4",

    "angular-cookies": "~1.4.0"

  }

}

注意: 不要随便修改该档,很容易出错的。必须用 Json 工具。 

静态程式如 AngularJS 不方便在 Eclipse 或 STS 内操作(可以处理的,不过是烦了一点),所以笔者喜欢用 Intelli J Idea 直接打开目录就可以看到全部的档案了。

图4:Car-Client 所需的AngularJS 架构及其程式名称

 

前端程式也很简单,重要的代码文档祇有4个,其他一般读者都会明白的。以下就解释一下这几个档案。

Index.hml  起动档案,部署有关的附属工具/包/界面等来保证程式运作正常。

<!DOCTYPE html>
<html>
<head lang="en">
    <title>Angularjs Spring-boot example</title>
    <script src="plugin/angular/angular.js"></script>
    <script src="plugin/angular-ui-router/angular-ui-router.min.js"></script>
    <script src="app/js/app.js"></script>
    <script src="app/js/ProductController.js"></script>
    <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.4/css/bootstrap.min.css"> -->
   
<link rel="stylesheet" href="plugin/bootstrap-3.3.4-css/bootstrap.min.css">
    <link rel="stylesheet" href="app/css/app.css">
</head>
<body ng-app="springApp">
    <div ui-view></div>
</body>
</html

app.js  - AngularJS 设定有关状况及指令

var springApp = angular.module('springApp',['ui.router'])

springApp.config(function($stateProvider, $urlRouterProvider) {

    $urlRouterProvider.otherwise('/home');
    $stateProvider
        .state('home', {
            url: '/home',
            templateUrl: 'app/html/present.html',
            controller:'productController'
       
});
});
springApp.directive('ngConfirmClick', [ function() {
    return {
        link : function(scope, element, attr) {
            var msg = attr.ngConfirmClick || "Are you sure?";
            var clickAction = attr.confirmedClick;
            element.bind('click', function(event) {
                if (window.confirm(msg)) {
                    scope.$eval(clickAction)
                }
            });
        }
    };
} ])

present.html - 这是界面与用户互动画面。/*** Created by sam8881 on 2016/8/22*<div class="inner"

<div class="generic-container">
            <div class="panel panel-default">
                <div class="panel-heading"><span class="lead">Car Entry Form </span></div>
                <div class="formcontainer">
                <table>
                <div class="row">
                    <div class="form-group col-md-12">
                        <label class="col-md-2 control-lable" for="Car Make">Car Make</label>
                        <div class="col-md-7">
        <input type="text"  ng-model="car.make" class="form-control input-sm" placeholder="Enter the make of the car."/>
                        </div>
                    </div>
                </div>
                <div class="row">
                        <div class="form-group col-md-12">
                            <label class="col-md-2 control-lable" for="Car Model">Car Model</label>
                        <div class="col-md-7">
      <input type="text"   ng-model="car.model" class="form-control input-sm" placeholder="Enter the model of the car. "/>
                        </div>
                        </div>
                </div>
                <div class="row">
                        <div class="form-group col-md-12">
                            <label class="col-md-2 control-lable" for="Car Description">Car Description</label>
                            <div class="col-md-7">
<input type="text"  ng-model="car.description" class="form-control input-sm" placeholder="Enter the description of the car. "/>
                        </div>
                        </div>
                </div>
                <div class="row">
                        <div class="form-group col-md-12">
                            <label class="col-md-2 control-lable" for="Year of Car">Year of Car</label>
                            <div class="col-md-7">
                            <input type="text"  value="" ng-model="car.year" class="form-control input-sm" placeholder="Enter the year of the car. "/>
                        </div>
                        </div>
                </div>
                <div class="row">
                    <div class="floatRight">
                            <input type="submit" name="submit" class="btn btn-primary btn-sm custom-width" value="Submit" ng-click="save();"/>
                            <input type="submit" name="clear" class="btn btn-warning btn-sm custom-width" value="Clear" ng-click="car = null"/>
                    </div>
                </div>
                </table>
            </div>
        </div>
               <div class="panel panel-default">  
                <div class="formcontainer">
             <form ng-init="acar=null" ng-submit="search(acar)" method="POST">
             <div class="row">
             <div class="form-group col-md-12">
             <label class="col-md-2 control-lable" for="Info">Search Information</label>
             <div class="col-md-7">
      <input type="text"  ng-model="acar" class="form-control input-sm" placeholder="Enter search of the car"/>
          </div>
            </div>
            <div class="floatRight">
            <input type="submit" name="search" class="btn btn-primary btn-sm custom-width" value="Search" />
            <input type="submit" name="clear" class="btn btn-warning btn-sm custom-width" value="Clear" ng-click="acar = null"/>
            </div>
            </div>
            </form>
            </div>
        </div>
            <div class="panel panel-default">
                <!-- Default panel contents -->
               
<div class="panel-heading"><span class="lead">List of Cars </span></div>
                <td class="tablecontainer">
                <table class="table table-hover">
                    <thead>
                        <tr>
                            <th>No</th>
                            <th>Car Make</th>
                            <th>Car Model</th>
                            <th>Description</th>
                            <th>Car of Year</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr ng-repeat="car in cars">
                            <td>{{$index + 1}}</td>
                            <td>{{car.make}}</td>
                            <td>{{car.model}}</td>
                            <td>{{car.description}}</td>
                            <td>{{car.year}}</td>
                            <td>
                                <div class="floatRight">
                            <button type="button" ng-click="updateCar(car);" class="btn btn-success custom-width">Edit</button>
                            <button type="button" confirmed-click="deleteCar(car);" ng-confirm-click=" Do you want to delete this car?" class="btn btn-danger custom-width">Delete</button>
                            </div>
                            </td>
                        </tr>
                    </tbody>
                </table>
                </td>
            </div>
            </div>
            </div>
</div>

CarController.js 这是前端程式核心机能,通过运用 $http api,负责和后台接收及输送资讯,这样才可以和服务器完全分离开发。前端工作者可以自由处理画面上的图示和表格,只要数据是正确,其他因素和后端没有什么关系。 /** * Created by sam8881 on 2016/8/22 */(function() {

   var productController = function($scope,$http) {
        var getListOfCar = function() {
         var response = $http({
                method: 'GET',
                url: "http://localhost:8080/api/getListOfCar"
           
}).success(function(data, status, headers, config) {
                $scope.cars = data;
           }).error(function(err, status, headers, config) {
                console.log(err);
            });
        }
     $scope.save = function() {
            var response = $http({
                method: 'POST',
                url: "http://localhost:8080/api/save",
                data : $scope.car
           
}).success(function(data, status, headers, config) {
                $scope.car = null;
                getListOfCar();
            }).error(function(err, status, headers, config) {
                console.log(err);
            });
        }
        $scope.search = function(acar) {
            var response = $http({
                method: 'POST',
                url: "http://localhost:8080/api/search",
                data:$params=acar,
  }).success(function(data) {
                $scope.car = data;
                getListOfCar();
                console.log(data);
                console.log("success!");
            }).error(function(err, status, headers, config) {
                console.log(err);
            });
        }
        $scope.updateCar = function(car) {
            $scope.car = car;
            getListOfCar();
        }
      $scope.deleteCar = function(car) {
            var response = $http({
                method: 'POST',
                url: "http://localhost:8080/api/delete",
                data : car
            }).success(function(data, status, headers, config) {
                getListOfCar();
            }).error(function(err, status, headers, config) {
                console.log(err);
            });
        }
       getListOfCar();
    };
productController.$inject = ['$scope','$http'];
  angular.module('springApp').controller('productController', productController);
}());

 注: 比较花时间还是有关 Css, 笔者有点懒,偷偷用了人家的 Css,加以改良一下。

测试

首先要启动资料库 MongoDB,建议使用 RoboMongo,容易查询资料。

打开一个 terminal 或 cmd,cd 到那有cars.dat的目录里,准备输入所提供的资料到MongoDB:

  mongoimport -d car_dealer -c cars cars.dat

 然后打开 MongoDB,确定这些汽车资源在库存。

有了汽车资料,就可以开始测试了。首先是打开 STS,在右边选择了该服务器程式,按右键操作:

product-server =>Run As => Spring Boot App 。如果你可以在 console 里看到com.emo.product.app 在等候,该服务器正在运作了。有读者可能问,画面呢?去了那里?他可能不记得前后端分离处理的,前台都没有开始,那有画面呢!注: 如果不想在 STS/Eclipse 上运行,可以在 terminal/cmd 进入该 product-server的目录内,输入: mvn spring-boot:run 也同样可以启动服务器。

启动前端更容易,打开那个 car-client 的视窗或 Mac的 finder,在 car-cleint的目录内(不用在 terminal 内开启的)选择了该index.html程式,按右键选取浏览器(Firefox)操作,如无意外,画面就出现在你的眼前。

 

图5:Spring Boot + Angular UI-Route + Mongodb CRUD学习程式

图6:输入S4按 search 键

图7:输入Honda 按 Submit 键来增加

图8: Honda 汽车资料已保存

一个简易又清楚的程式开发过程全部显示了。也可能作为一个模版作将来的 Web 的开发。所以要处理当然是页数及搜索的速度。因为现在是全方位的资料库搜查, MongoDB 是十分成任的。

 

如果您觉得本文的内容对您的学习或工作有所帮助,您可以赞助来支持我,您的认同就是我动力!支付微信在顶部。多少不拘,5元,10元,20元。。。心意而已!

 

原创,如有转载,请注明出处!

 

笔者以往分享的记录:

jHipster 3.4  创建最流行Java Web应用项目最简单的入门基本教程

原精PHP5.2.9+MySQL5.6.26+Easyui 1.41开发易贸达出入口公司产品查询浏览表

 

 

 

---恢复内容结束---

posted @ 2016-08-22 15:06  sam8881  阅读(1816)  评论(0编辑  收藏  举报