Spring Boot1.3.6 Angularjs1.4.0 Mongodb2.3.6 CRUD汽车搜索及增加修改程式
一个实用的编程例子,让读者认真地体会本文的要点。
- 传统学习编程技术落后,应跟著潮流,要对业务聚焦处理。
- 要Jar, 不要War;以小为主,以简为宝,集堆而成。
- 去繁取简 Spring Boot,明日之春。
- 集堆综合技术如 jHipster 是必然的软件开发途径
- 前后端分离技术,跨域资源共享( CORS)。
以一个 Spring Boot + Angular UI-Route + Mongodb CRUD学习程式资料. 笔者要用最简单又有效的编程方法来实践“ 以小为主,以简为宝 ” 的原则。首先什么是小呢?程式可分成前后端分开处理,都是以 MVC 模式安排,加上用跨域资源共享( CORS)来分成前后端的开发。换句话说,前后端各自开发,祇有在程式运作时才有直接数据来往。
后端的开发:Spring Boot + mongoDB + H2
- 打开你常用的浏览器, 在 URL 输入https://stat.spring.io
- 在页面上输入:
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学习程式
一个简易又清楚的程式开发过程全部显示了。也可能作为一个模版作将来的 Web 的开发。所以要处理当然是页数及搜索的速度。因为现在是全方位的资料库搜查, MongoDB 是十分成任的。
原创,如有转载,请注明出处!
笔者以往分享的记录:
猜你喜欢
- Swagger的简单案例,适合初级者学习使用
- Springboot+thymeleaf对员工的增删改查操作 带分页功能
- springboot2.x+mybatis-plus+jsp+jpa简单增删改查实例(仅供学习)
- spring boot+mybatis+mysql基础配置实现部门数据增加查询更新功能
- mac下spring boot基础增删改查项目实例
- IntelliJ IDEA下SpringBoot+Maven+Spring Data JPA+Layui整合实现增删改查及分页的单表项目实例
- 基于spring boot整合dubbo实现简单的增删改查案例
- springboot+angularJS简单的增删改查Demo
- springboot+jpa+bootstrap+mysql用户登录+增删改查 运行环境为IDEA
- Spring Boot+SpringData JPA整合实现用户增删改查及其分页查询简单实战项目
- Spring Boot+Maven+Spring Data JPA+Layui整合实现增删改查及分页的多表查询项目实例
- spring boot+mybatis+layui构建的用户增删改查实例,支持分页查询,模糊查询
- /
- /car
- /car/client
- /car/client/.DS_Store
- /car/client/.bowerrc
- /car/client/.idea
- /car/client/.idea/.name
- /car/client/.idea/angular-auth.iml
- /car/client/.idea/compiler.xml
- /car/client/.idea/copyright
- /car/client/.idea/copyright/profiles_settings.xml
- /car/product-server
- /car/product-server/src
- /car/product-server/src/main
- /car/product-server/src/main/java
- /car/product-server/src/main/java/com
- /car/product-server/src/main/java/com/emo
- /car/product-server/src/main/java/com/emo/product
/car/product-server/src/main/java/com/emo/product/app.java
- /car/product-server/src/main/java/com/emo/product/config
- /car/product-server/src/main/java/com/emo/product/controllers
- /car/product-server/src/main/java/com/emo/product/model
- /car/product-server/src/main/java/com/emo/product/repository
- /car/product-server/src/main/java/com/emo/product
- /car/product-server/src/main/java/com/emo
- /car/product-server/src/main/java/com
- /car/product-server/src/main/java
- /car/product-server/src/main
- /car/product-server/src
- /car/client
- /car

- 证 Spring Boot创建自定义Banner.txt实例
- 证 Spring Boot配置@Profile注解加载不同环境的配置文件实例
- 证 Spring Boot Actuator 2.3.4.RELEASE新版本实现自定义端点信息的配置实例
- 原证 spring AOP 过滤器 拦截器 执行顺序示例
- 证 spring boot使用不指定Maven parent pom来创建可执行的spring boot项目
- 证 Spring Boot整合thymeleaf做为显示层的hello world实例
- 证 Spring Boot整合SpringFox Swagger2实现REST API增删改查项目实例
- 证 Spring Boot演示@ConfigurationProperties标注实现自定义配置属性的实例
- 证 Spring Boot整合Ehcache的简单入门实例
- 原证 springboot+sqlite3+iceEditor开发网页版记事本
- 原证精 SpringBoot+Maven+Echarts实现实时展示CPU内存硬盘性能
- 原证 Swagger的简单案例,适合初级者学习使用

