Spring Boot的web开发

来源:互联网 发布:mac系统可以装ps吗 编辑:程序博客网 时间:2024/06/06 04:48
基于Bootstrap和AngularJS的现代Web应用
现代的B/S系统特色
1.单页面应用(single-page application,简称SPA)
所有资源(html、js、css)都按需动态加载到页面上,且不需要服务端控制页面页面的转向
2.响应式设计(Responsive web design,简称RWD)
不同设备访问相同页面,得到不同页面视图,得到的视图是适应当前屏幕的。
3.数据导向
针对于页面导向而言,页面上的数据获得是通过消费后台的REST服务来实现的,而不是通过服务器渲染的动态页面实现,一般数据交换使用的格式是JSON
1.Bootstrap
Bootstrap定义:Bootstrap是开发响应式和移动优先的Web应用的最流行的HTML、css、JavaScript框架
Bootstrap实现了只使用一套代码就可以在不同设备显示你想要的视图的功能。提供了大量美观的HTML元素前端组件和jQuery插件。
1.1 下载并引入Bootstrap
下载地址:http://getbootstrap.com/getting-started/
1.2 CSS支持
Bootstrap的CSS样式为基础的HTML元素提供了美观的央视,此外提供了高级的网格系统用来做页面布局。简单的页面模板:
<!DOCTYPEhtml>
<htmllang="zh-cn">
<!-- 上面两句为HTML5的doctype -->
<head>
<metacharset="utf-8">
<metahttp-equiv="X-UA-Compatible"content="IE=edge">
<metaname="viewport"content="width=device-width, initial-scale=1">
<!-- 上面3个meta标签必须是head的头三个标签,其余的head内标签在此3个之后The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Bootstrap基本模板</title>

<!-- Bootstrap的CSS -->
<linkhref="bootstrap/css/bootstrap.min.css"rel="stylesheet">
<!-- HTML5 shim and Respond.js用来让IE8支持HTML5元素和媒体查询 -->
<!--[if lt IE 9]>
<script src="js/html5shiv.min.js"></script>
<script src="js/respond.min.js"></script>
<![endif]-->
</head>
<body>
<h1>你好, Bootstrap!</h1>
<!-- jQuery是Bootstrap脚本插件必须的 -->
<scriptsrc="js/jquery.min.js"></script>
<!-- 包含所有编译的插件 -->
<scriptsrc="bootstrap/js/bootstrap.min.js"></script>
</body>
</html>
1.2.1 布局网格
在Bootstrap里,行使用的样式为row,列使用col-md-数字,此数字范围为1-12,所有列加起来的和也是12.
<divclass="row">
<divclass="col-md-1">.col-md-1</div>
<divclass="col-md-1">.col-md-1</div>
<divclass="col-md-1">.col-md-1</div>
<divclass="col-md-1">.col-md-1</div>
<divclass="col-md-1">.col-md-1</div>
<divclass="col-md-1">.col-md-1</div>
<divclass="col-md-1">.col-md-1</div>
<divclass="col-md-1">.col-md-1</div>
<divclass="col-md-1">.col-md-1</div>
<divclass="col-md-1">.col-md-1</div>
<divclass="col-md-1">.col-md-1</div>
<divclass="col-md-1">.col-md-1</div>
</div>
<divclass="row">
<divclass="col-md-8">.col-md-8</div>
<divclass="col-md-4">.col-md-4</div>
</div>
<divclass="row">
<divclass="col-md-4">.col-md-4</div>
<divclass="col-md-4">.col-md-4</div>
<divclass="col-md-4">.col-md-4</div>
</div>
<divclass="row">
<divclass="col-md-6">.col-md-6</div>
<divclass="col-md-6">.col-md-6</div>
</div>
1.2.2 html元素
Bootstrap为html元素提供了大量的样式,如表单元素、按钮等,具体内容查看http://getbootstrap.com/css
1.3 页面组件支持
Bootstrap提供了大量的页面组件,包括字体图标、下拉框等,更多阅读http://getbootstrap.com/components/
1.4 javascript支持
Bootstrap提供大量JavaScript插件,如模式对话框、标签页、提示灯,更多阅读http://getbootstrap.com/javascript/

2.AngularJS
AngularJS定义:是HTML开发本应该的样子,用来设计开发Web应用的。
AngularJS使用声明式模板+数据绑定(类似JSP、Thymeleaf)、MVW(Model-View-Whatever)、MVVM(Model-View-ViewModel)、MVC(Model-View-Controller)、依赖注入和测试,这一切实现只借助纯客户端的JS。
HTML用来声明静态页面,AngularJS可以只通过前端技术就实现动态的页面。
2.1 下载并引入AngularJS
下载地址:https://angularjs.org
简单的页面代码:
<!doctypehtml>
<htmlng-app><!-- ng-app所作用的范围是AngularJS起效的范围,本例是整个页面有效 -->
<head>
<metacharset="utf-8">
<scriptsrc="js/angular.min.js"></script><!-- 载入AngularJS的脚本 -->
</head>
<body>
<div>
<label>名字:</label>
<inputtype="text"ng-model="yourName"placeholder="输入你的名字"><!-- ng-model定义整个AngularJS的前端数据模型,模型的名称为yourName,模型的值来自你输入的值,若输入值改变,则数据模型值也改变。 -->
<hr>
<h1>你好 {{yourName}}!</h1><!-- 使用{{模型名}}来读取模型中的值 -->
</div>
</body>
</html>

2.2 模块、控制器和数据绑定
用AngularJS实现纯页面端的MVC,即实现了视图模板、数据模板、代码控制的分离
数据绑定是将视图和数据模型绑定在一起。如果视图变了,模型的值也随着变了,反之一样。
AngularJS为了分离代码达到复用的效果,提供了一个module(模块)。定义一个模块需要下面的代码。
无依赖模块:angular.module('firstModule',[]);
有依赖模块:angular.module('firstModule',['moduleA','moduleB']);
V就是页面元素,M就是ng-model,C就是ng-controller(页面通过ng-controller来与其关联)
angular.module('firstModule',[])
.controller('firstController',function(){
.....
};
);

<div ng-controller="firstController">
...
</div>
2.3 Scope和Event
(1) Scope
Scope是AngularJS的内置对象,用$Scope获得。在Scope中定义的数据是数据模型,可以通过
{{模型名}}在视图上获得。
Scope主要是在编码中需要对数据模型进行处理的时候使用。
Scope的作用范围与在页面声明的范围一致(如在controller内使用,scope的作用范围是页面声明2ng-controller标签元素的作用范围)
定义:$scope.greeting='Hello'
获取:{{greeting}}
(2)Event
因为Scope的作用范围不同,所以不同的Scope之间若要交互的话需要通过事件(Event)来完成
1)冒泡事件(Emit)冒泡事件负责从子Scope向上发送事件
子Scope发送:
$scope.$emit('EVENT_NAME_EMIT',''message);
父Scope接受:
$scope.$on(''EVENT_NAME_EMIT',function(event,data){
.......})
2)广播事件(Broadcast).广播事件负责从父Scope向下发送事件。
父Scope发送:
$scope.$broadcast('EVENT_NAME_BROAD','message');
子scope接受:
$scope.$on(''EVENT_NAME_BROAD',function(event,data){
.......})
2.4 多视图和路由
多视图和路由是AngularJS实现单页面应用的技术关键,AngularJS内置了一个$routeProvider对象来负责页面加载和页面路由转向。
注意:1.2.0之后的AngularJS将路由功能移出所以使用路由功能要另外引入angular-route.js
例如:
angular.module('firstModule').config(function($routeProvider){
$routeProvider.when('/view1',{//此处定义的是某个页面的路由名称
controller:'Controller1',//此处定义的是当前页面使用的控制器
templateUrl:'view1.html',//此处定义的是加载的真实页面
}).when('/view2',{
controller:'Controller2',
templateUrl:'view2.html',
});
})

在页面上可以用下面代码来使用我们定义的路由:
<ul>
<li><a href="#/view1">view1</a></li>
<li><a href="#/view2">view2</a></li>
</ul>
<ng-view></ng-view><!--此处为加载进来的页面显示的位置-->

2.5 依赖注入
依赖注入是AngularJS的重要功能,可以实现对代码的解耦,在代码里可以注入AngularJS的对象或者我们自定义的对象。
在控制器注入$scope,注意使用依赖注入的代码格式:
angular.module('firstModule').controller("diController",{'$scope',function($scope){
.........}});

2.6 Service和Factory
AngularJS内置了一些服务,如$location、$timeout、$root.
自己定制服务,AngularJS提供了Service和Factory
Service:AngularJS使用new来初始化对象
Factory:直接获得对象
(1) Service
定义:
angular.module('firstModule').service('helloService',function(){
this.sayHello=function(name){
alert('Hello'+name);
}
});
注入调用:
angular.module('firstModule').controller("diController",['$scope','helloService',
function($scope,helloService){
helloService.sayHello('lqy');
}]);
(2) Factory
定义:
angular.module('firstModule'.service('helloFactory',function(){
return{
sayHello:function(name){
alert('Hello'+name);
}
}
}));
注入调用:
angular.module('firstModule').controller("diController",['$scope','helloFactory',
function($scope,helloFactory){
helloFactory.sayHello('lqy');
}]);
2.7 自定义指令
AngularJS内置了大量的指令(directive),如ng-repeat、ng-show、ng-model等。即使用一个简短的指令可实现一个前端组件。
举例:一个日期的js/jQuery插件,使用AngularJS封装后,在页面上调用该插件可以通过指令实现。
元素指令:<date-picker></date-picker>
属性指令:<input type="text" date-picker/>
样式指令:<input type="text" class="date-picker"/>
注释指令:<!-- directive;date-picker-->
定义指令:
angular.module('myApp',[]).directive('helloWorld',function(){
return {
restrict:'AE',//支持使用属性、元素
replace:true,
template:'<h3>Hello,World!</h3>'
};
});
调用指令,元素标签:
<hello-world/>
<hello:world/>
属性方式:
<div hello-world/>


实战
使用Bootstrap制作导航,使用AngularJS实现导航切换页面的路由功能,
并演示AngularJS通过$http服务和Spring Boot提供的REST服务,最后演示用指令封装jQueryUI的日期选择器。
1.新建Spring Boot项目
选择Web依赖(spring-boot-starter-web)
准备Bootstrap、AngularJS、jQuery、jQueryUI相关的资源到src/main/resources/static下。(静态页面统一放到static下)

2.制作导航
页面位置:src/main/resources/static/action.html
<!DOCTYPEhtml>
<htmllang="zh-cn"ng-app="actionApp">
<head>
<metacharset="utf-8">
<metahttp-equiv="X-UA-Compatible"content="IE=edge">
<metaname="viewport"content="width=device-width, initial-scale=1">
<title>实战</title>
<!-- Bootstrap的CSS -->
<linkhref="bootstrap/css/bootstrap.min.css"rel="stylesheet">
<linkhref="jqueryui/jquery-ui.min.css"rel="stylesheet">
<styletype="text/css">

.content{
padding:100px15px;
text-align:center;
}
</style>
<!--[if lt IE 9]>
<script src="js/html5shiv.min.js"></script>
<script src="js/respond.min.js"></script>
<![endif]-->
</head>
<!--使用Bootstrap定义的导航,并配合AngularJS的路由,通过路由名称#/oper和#/directive切换视图 -->
<body>
<navclass="navbar navbar-inverse navbar-fixed-top">
<divclass="container">
<divid="navbar"class="collapse navbar-collapse">
<ulclass="nav navbar-nav">
<li><ahref="#/oper">后台交互</a></li>
<li><ahref="#/directive">自定义指令</a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
<!--通过<ng-view></ng-view>展示载入的页面-->
<divclass="content">
<ng-view></ng-view>
</div>
<!--加载本例所需的脚本,其中jquery-ui.min.js的脚本是为定制指令所用;
app.js定义AngularJS的模块和路由;
directives.js为自定义的指令;
controllers.js是控制器定义之处 -->
<scriptsrc="js/jquery.min.js"></script>
<scriptsrc="jqueryui/jquery-ui.min.js"></script>
<scriptsrc="bootstrap/js/bootstrap.min.js"></script>
<scriptsrc="js/angular.min.js"></script>
<scriptsrc="js/angular-route.min.js"></script>
<scriptsrc="js-action/app.js"></script>
<scriptsrc="js-action/directives.js"></script>
<scriptsrc="js-action/controllers.js"></script>
</body>
</html>
3.模块和路由定义
页面位置:src/main/resources/static/js-action/app.js
/**
*
*/
varactionApp=angular.module('actionApp',['ngRoute']);//定义模块actionApp,并依赖于路由模块ngRoute
actionApp.config(['$routeProvider',function($routeProvider) {//配置路由,并注入$routeProvider来配置
$routeProvider.when('/oper', { //oper为路由名称
controller:'View1Controller',//controller定义的是路由的控制器名称
templateUrl:'views/view1.html',//templateUrl定义的是视图的真正地址
}).when('/directive', {
controller:'View2Controller',
templateUrl:'views/view2.html',
});
}]);
4.控制器定义
脚本位置:src/main/resources/static/js-action/controllers.js
/**
*
*/
//定义控制器View1Controller,并注入$rootScope、$scope和$http
actionApp.controller('View1Controller', ['$rootScope','$scope','$http',
function($rootScope, $scope,$http) {
//使用$scope.$on监听$viewContentLoaded事件,可以在页面内容加载完成后进行一些操作
$scope.$on('$viewContentLoaded',function() {
console.log('页面加载完成');
});
//这段代码是演示的核心代码,结合View的界面一起理解:
/**
* 1.在scope内定义一个方法search,在页面上通过ng-click调用。
* 2.通过$scope.personName获取页面定义的ng-model="personName"的值
* 3.使用$http.get向服务端地址search发送get请求
* 4.使用params增加请求参数。
* 5.用success方法作为请求成功后的回调
* 6.将服务器返回的数据data通过$scope.person赋给模型person,
* 这样页面视图上可以通过{{person.name}}、{{person.age}}、{{person.address}}来调用,
* 且模型person值改变后,视图是自动更新的。
*/
$scope.search=function(){//1
personName= $scope.personName;//2
$http.get('search',{//3
params:{personName:personName}//4
}).success(function(data){//5
$scope.person=data;//6
});;
};
}]);
actionApp.controller('View2Controller', ['$rootScope','$scope',function($rootScope, $scope) {
$scope.$on('$viewContentLoaded',function() {
console.log('页面加载完成');
});
}]);
5.View1的界面(演示与服务端交互)src/main/resources/static/views/view1.html
<divclass="row">
<labelfor="attr"class="col-md-2 control-label">名称</label>
<divclass="col-md-2">
<!-- 定义数据模型ng-model="personName" -->
<inputtype="text"class="form-control"ng-model="personName">
</div>
<divclass="col-md-1">
<!-- 通过ng-click="search()"调用控制器中定义的方法 -->
<buttonclass="btn btn-primary" ng-click="search()">查询</button>
</div>
</div>
<divclass="row">
<divclass="col-md-4">
<ulclass="list-group">
<!-- 通过{{person.name}}、{{person.age}}、{{person.address}}访问控制器的scope里定义person模型,模型和视图是绑定的 -->
<liclass="list-group-item">名字: {{person.name}}</li>
<liclass="list-group-item">年龄: {{person.age}}</li>
<liclass="list-group-item">地址: {{person.address}}</li>
</ul>
</div>
</div>

6.服务端 代码
传值对象Javabean:
packagecom.hand;

public classPerson {
privateStringname;
privateIntegerage;
privateStringaddress;
publicPerson() {
super();
}
publicPerson(String name, Integer age, String address) {
super();
this.name= name;
this.age= age;
this.address= address;
}
publicString getName() {
returnname;
}
public voidsetName(String name) {
this.name= name;
}
publicInteger getAge() {
returnage;
}
public voidsetAge(Integer age) {
this.age= age;
}
publicString getAddress() {
returnaddress;
}
public voidsetAddress(String address) {
this.address= address;
}
}
7.自定义指令:src/main/resources/static/js-action/directives.js;
/**
* 定制了一个封装jqueryui的datePicker的指令
*/
actionApp.directive('datePicker',function(){//定义一个指令名为datePicker
return{
restrict:'AC',//限制为属性指令和样式指令
link:function(scope,elem,attrs){//使用link方法来定义指令,在Link方法内可使用当前scope,当前元素及元素属性
// scope.treeObj = $.fn.zTree.init(elem, scope.settings);
elem.datepicker();//初始化jqueryui的dataPicker(jquery的写法是$('#id').dataPicker())
}
};
});
8.View2的页面(演示自定义指令)
<divclass="row">
<labelfor="attr"class="col-md-2 control-label">属性形式</label>
<divclass="col-md-2">
<!-- 使用属性形式调用指令 -->
<inputtype="text"class="form-control"date-picker>
</div>
</div>
<divclass="row">
<labelfor="style"class="col-md-2 control-label">样式形式</label>
<divclass="col-md-2">
<!-- 使用样式形式调用指令 -->
<inputtype="text"class="form-control date-picker" >
</div>
</div>
9.运行