爱编程的小叮当

爱编程的小叮当 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 个人简介什么都没有

个人动态

爱编程的小叮当 发布了文章 · 1月25日

你知道可以通过网址访问的Servlet如何实现吗?

Servlet生命周期实现方式

  • 实例和初始化时机
  • 就绪/调用/服务阶段
  • 销毁时机

案例实操

Servlet 的生命周期

Servlet 没有 main() 方法,不能独立运行,它的运行完全由 Servlet 引擎来控制和调度。所谓生命周期,指的是 servlet 容器何时创建 servlet 实例、何时调用其方法进行请求的处理、并何时销毁其实例的整个过程。(此处讨论默认的生命周期)

  • 实例和初始化时机

当请求到达容器时,容器查找该 servlet 对象是否存在,如果不存在,则会创建实例并进行初始化。

  • 就绪/调用/服务阶段

有请求到达容器,容器调用 servlet 对象的 service() 方法,处理请求的方法在整个生命周期中可以被多次调用;

HttpServlet 的 service() 方法,会依据请求方式来调用 doGet() 或者 doPost() 方法。但是,这两个 do 方法默认情况下,会抛出异常,需要子类去 override。

  • 销毁时机

当容器关闭时(应用程序停止时),会将程序中的 Servlet 实例进行销毁。

上述的生命周期可以通过 Servlet 中的生命周期方法来观察。在 Servlet 中有三个生命周期方法,不由用户手动调用,而是在特定的时机由容器自动调用,观察这三个生命周期方法即可观察到 Servlet 的生命周期。

init 方法,在 Servlet 实例创建之后执行(证明该 Servlet 有实例创建了)

public void init(ServletConfig config) throws ServletException {
System.out.println("有实例创建了");
}

service 方法,每次有请求到达某个 Servlet 方法时执行,用来处理请求(证明该 Servlet 进行服务了)

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("服务调用了");
}

destroy 方法,Servlet 实例销毁时执行(证明该 Servlet 的实例被销毁了)

public void destroy() {
System.out.println("有实例被销毁了");
}

Servlet 的生命周期,简单的概括就分为四步:servlet 类加载→实例化→服务→销毁。下面我们描述一下 Tomcat 与 Servlet 是如何工作的,看看下面的时序图:

1、Web Client 向 Servlet 容器(Tomcat)发出 Http 请求

2、Servlet 容器接收 Web Client 的请求

3、Servlet 容器创建一个 HttpRequest 对象,将 Web Client 请求的信息封装到这个对象中

4、Servlet 容器创建一个 HttpResponse 对象

5、Servlet 容器调用 HttpServlet 对象的 service 方法,把 HttpRequest 对象与 HttpResponse 对象作为参数,传给 HttpServlet 对象

6、HttpServlet 调用 HttpRequest 对象的有关方法,获取 Http 请求信息

7、HttpServlet 调用 HttpResponse 对象的有关方法,生成响应数据

8、Servlet 容器把 HttpServlet 的响应结果传给 Web Client

扩展

Servlet 的配置

Servlet 除了配置基本的访问信息,还可以配置初始化参数,自启动等,并且一个 Servlet 可以配置多个访问路径,还可以使用通配符“*”。

基本配置

<servlet>
<servlet-name>helloweb</servlet-name><!-- 给服务器看的 -->
<servlet-class>com.xxx.web.HelloWeb</servlet-class><!-- servlet对应的资源路径 -->
</servlet>
<servlet-mapping>
<servlet-name>helloweb</servlet-name><!-- 给服务器看的 -->
<url-pattern>/helloweb</url-pattern><!-- 给浏览器看的,对外访问路径 -->
<url-pattern>/*</url-pattern>
</servlet-mapping>

初始化参数

<servlet>
<servlet-name>helloweb</servlet-name><!-- 给服务器看的 -->
<servlet-class>com.xxx.web.HelloWeb</servlet-class><!-- servlet对应的资源路径 -->
<!-- 初始化参数 -->
<init-param>
<param-name>param1</param-name>
<param-value>1</param-value>
</init-param>
<init-param>
<param-name>param2</param-name>
<param-value>2</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>helloweb</servlet-name><!-- 给服务器看的 -->
<url-pattern>/helloweb</url-pattern><!-- 给浏览器看的,对外访问路径 -->
<url-pattern>/*</url-pattern>
</servlet-mapping>

自启动

<servlet>
<servlet-name>helloweb</servlet-name><!-- 给服务器看的 -->
<servlet-class>com.xxx.web.HelloWeb</servlet-class><!-- servlet对应的资源路径 -->
<!-- 初始化参数 -->
<init-param>
<param-name>param1</param-name>
<param-value>1</param-value>
</init-param>
<init-param>
<param-name>param2</param-name>
<param-value>2</param-value>
</init-param>
<!-- 自启动 -->
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>helloweb</servlet-name><!-- 给服务器看的 -->
<url-pattern>/helloweb</url-pattern><!-- 给浏览器看的,对外访问路径 -->
<url-pattern>/*</url-pattern>
</servlet-mapping>

servlet-name:Servlet 对象的名称

servlet-class:创建 Servlet 对象所要调用的类

param-name:参数名称

param-value:参数值

load-on-startup:Servlet 容器启动时加载 Servlet 对象的顺序

servlet-mapping/servlet-name:要与 servlet 中的 servlet-name 配置的内容对应

url-pattern:客户访问的 Servlet 的相对 URL 路径

说明:url-pattern 可以配多个(一个 servlet 可以通过多个 url-pattern 访问)当多个 servlet 配置成了同一个 url-pattern,报错 java.lang.reflect.InvocationTargetExceptionion;通配符“*”只能放在最前面或最后面,不能放中间且不能单独存在(以/分割的,不能和单词组成整体)。越精确越优先。常规配置即可。

查看原文

赞 0 收藏 0 评论 0

爱编程的小叮当 发布了文章 · 1月22日

知识分享:JavaScript基础语法

JavaScript

简介

JavaScript 是一种具有面向对象能力的、解释型的程序设计语言。更具体一点,它是基于对象和事件驱动并具有相对安全性的客户端脚本语言。它的主要目的是,验证发往服务器端的数据、增加 Web 互动、加强用户体验度等。

JavaScript 的组成

ECMAScript定义的只是这门语言的基础,与Web浏览器没有依赖关系,而在基础语法上可以构建更完善的脚本语言。JavaScript的运行需要一定的环境,脱离了环境JavaScript代码是不能运行的,JavaScript只能够寄生在某个具体的环境中才能够工作。JavaScript运行环境一般都由宿主环境和执行期环境共同构成,其中宿主环境是由外壳程序生成的,如Web浏览器就是一个外壳程序,它提供了 一个可控制浏览器窗口的宿主环境。执行期环境则由嵌入到外壳程序中的JavaScript引擎(或称为JavaScript解释器)生成,在这个环境中 JavaScript能够生成内置静态对象,初始化执行环境等。

Web浏览器自定义的DOM组件,以面向对象方式描述的文档模型。DOM定义了表示和修改文档所需的对象、这些对象的行为和属性以及这些对象之间的关系。DOM对象,是我们用传统的方法(javascript)获得的对象。DOM属于浏览器,而不是JavaScript语言规范里的规定的核心内容。

前面的DOM是为了操作浏览器中的文档,而为了控制浏览器的行为和操作,浏览器还提供了BOM(浏览器对象模型)。

ECMAScript(基础语法)

JavaScript的核心语法ECMAScript描述了该语言的语法和基本对象

DOM(文档对象模型)

文档对象模型(DOM)—— 描述了处理网页内容的方法和接口

BOM(浏览器对象模型)

浏览器对象模型(BOM)—— 描述了与浏览器进行交互的方法和接口

开发工具

  1. 浏览器:Chrome
  2. 开发工具:Hbuilder X
  3. 进入浏览器控制台 Console:F12

    控制台的作用:

    console对象代表浏览器的JavaScript控制台,用来运行JavaScript命令,常常用来显示网页运行时候的错误信息。Elements用来调试网页的html和css代码。

基本用法

JS需要和HTML一起使用才有效果,我们可以通过直接或间接的方式将JS代码嵌入在HTML页面中。

行内JS : 写在标签内部的js代码

内部JS : 定义在script标签内部的js代码

外部JS : 单独的js文件,在HTML中通过script标签引入

我们可以将JavaScript代码放在html文件中任何位置,但是我们一般放在网页的head或者body部分。由于页面的加载方式是从上往下依次加载的,而这个对我们放置的js代码运行是有影响的。

放在<head>部分,最常用的方式是在页面中head部分放置<script>元素,浏览器解析head部分就会执行这个代码,然后才解析页面的其余部分。

放在<body>部分,JavaScript代码在网页读取到该语句的时候就会执行。

行内 JS:

<button onclick="alert('you clicked hered!!!')">click here</button>

内部 JS:

<script type="text/javascript" charset="utf-8">
alert('this is inner js code')
</script>

外部 JS 文件:

hello.js

alert('this is a outter js document');

hello.html

<!-- 在需要使用js的html页面中引入 -->
<script data-original="js/hello.js" type="text/javascript" charset="utf-8"></script>

JavaScript基础语法

语句和注释

JavaScript程序的执行单位为行(line),也就是一行一行地执行。一般情况下,每一行就是一个语句。

语句(statement)是为了完成某种任务而进行的操作,语句以分号结尾,一个分号即表示一个语句结束。多个语句可以写在一行内(不建议这么写代码),但是一行写多条语句时,语句必须以分号结尾。

表达式不需要分号结尾。一旦在表达式后面添加分号,则JavaScript引擎就将表达式视为语句,这样会产生一些没有任何意义的语句。

单行注释:用//起头;
多行注释:放在//之间。
兼容html注释方式:<!-- -->

标识符和关键字

标识符就是一个名字,用来给变量和函数进行命名,有特定规则和规范

规则:

由Unicode字母、_、$、数字组成、中文组成
(1)不能以数字开头
(2)不能是关键字和保留字
(3)严格区分大小写

规范:

(1)见名知意
(2)驼峰命名或下划线规则

关键字也称保留字,是被JavaScript征用来有特殊含义的单词

arguments、break、case、catch、class、const、continue、debugger、default、delete、do、else、enum、eval、export、extends、false、finally、for、function、if、implements、import、in、instanceof、interface、let、new、null、package、private、protected、public、return、static、super、switch、this、throw、true、try、typeof、var、void、while、with、yield、Infinity、NaN、undefined

变量

变量即一个带名字的用来存储数据的内存空间,数据可以存储到变量中,也可以从变量中取出数据。

变量的声明

JavaScript是一种弱类型语言,在声明变量时不需要指明数据类型,直接用var修饰符进行声明。

变量声明和赋值:

// 先声明再赋值
var a ;
a = 10;
// 声明同时赋值
var b = 20;

变量的注意点

(1)若只声明而没有赋值,则该变量的值为undefined。

var box;
console.log(box);

(2)变量要有定义才能使用,若变量未声明就使用,JavaScript会报错,告诉你变量未定义。

console.log(box2);

(3)可以在同一条var命令中声明多个变量。

var a, b, c = 10;
console.log(a,b,c);

(4)若使用var重新声明一个已经存在的变量,是无效的。

var box = 10
var box;

(5)若使用var重新声明一个已经存在的变量且赋值,则会覆盖掉前面的值

var box = 10;
var box = 25;

(6)JavaScript是一种动态类型、弱类型语言,也就是说,变量的类型没有限制,可以赋予各种类型的值。

var box = 'hello world';
box = 10;

变量提升

JavaScript 引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升。

console.log(msg);
var msg = "so easy";

// 变量提升,相当于下面的代码
var msg;
console.log(msg);
msg = "so easy";

// 说明: 最后的结果是显示undefined,表示变量msg已声明,但还未赋值。

注意:变量提升只对 var 命令声明的变量有效,如果变量不是用 var 命令声明的,就不会发生变量提升。

console.log(msg);
msg = "error";

数据类型

虽说JS是弱类型语言,变量没有类型,但数据本身是有类型的。针对不同的类型,我们可以进行不同的操作。

JavaScript 中有6 种数据类型,其中有五种简单的数据类型:UndefinedNull布尔数值字符串。一种复杂数据类型Object

数 值(Number): 整数和小数(比如 1 和 3.14)
字符串(String): 字符组成的文本(比如"Hello World")
布尔值(Boolean):true(真)和 false(假)两个特定值
Undefined:       表示“未定义”或不存在,即此处目前没有任何值
Null:           表示空缺,即此处应该有一个值,但目前为空
对象(object)(引用) : 各种值组成的集合
1)、对象(object){name:”zhangsan”,age:”18”}
2)、数组(array)[1,2,3]
3)、函数(function)function test() {}

undefined

undefined类型的值是undefined。

undefined 是一个表示"无"的原始值,表示值不存在。

出现undefined的常见情况:

(1)当声明了一个变量而没有初始化时,这个变量的值就是undefined

var box;
console.log(box); //undefined

(2)调用函数时,该函数有形参,但未提供实参,则该参数为undefined。

function noData(str) { // js函数形参只需要变量名即可
console.log(str); // undefined
}
noData(); // 调用方法时,未传递参数

(3)函数没有返回值时,默认返回 undefined。

// 方法没有返回值
function noData() {
console.log("Hello");
}
var re = noData();// 定义变量接收无返回值的方法
console.log(re);

null

null类型是只有一个值的数据类型,即特殊的值null。它表示空值,即该处的值现在为空,它表示一个空对象引用。

使用Null类型值时注意以下几点:

1)使用typeof操作符测试null返回object字符串。

2)undefined派生自null,所以等值比较返回值是true。未初始化的变量和赋值为null的变量相等。

console.log(undefined == null);
var box = null; // 赋值为null的变量
var a; // 未初始化的变量
console.log(a == box); // 两个的值相等

布尔类型

布尔类型有两个值:true、false。常用来做判断和循环的条件

数值型

数值型包含两种数值:整型和浮点型。

1)所有数字(整型和浮点型)都是以 64 位浮点数形式储存。所以,JS中1 与 1.0 相等,而且 1 加上 1.0 得到的还是一个整数。浮点数最高精度是17位小数,由于浮点数运算时可能不精确,尽量不要使用浮点数做判断。

2)在存储数值型数据时自动将可以转换为整型的浮点数值转为整型。

console.log(1 == 1.0); // true
console.log(1 + 1.0); // 2
var num = 8.0; // 自动将可以转换为整型的浮点数转为整型
console.log(num); // 8

字符串

使用 ' ' 或 " "引起来,如:'hello',"good"。

使用加号 '+' 进行字符串的拼接,如:console.log('hello' + ' everybody');

对象

对象是一组数据和功能的集合。

说明:

{}:表示使用对象字面量方式定义的对象。空的大括号表示定义包含默认属性和方法的对象。

类型转换

自动类型转换

函数转换(String to Number)

JS 提供了 parseInt()parseFloat()两个全局转换函数。前者把值转换成整数,后者把值转换成浮点数。只有对 String 类型调用这些方法,这两个函数才能正确运行;对其他类型返回的都是 NaN(Not a Number)。

parseInt()

在转换之前,首先会分析该字符串,判断位置为0处的字符,判断它是否是个有效数字,如果不是,则直接返回NaN,不再继续,如果是则继续,直到找到非字符

parseInt("1234blue"); // returns 1234
parseInt("22.5"); // returns 22
parseInt("blue"); // returns NaN

parseFloat()

该方法与 parseInt() 方法的处理方式相似,从位置 0 开始查看每个字符,直到找到第一个非有效的字符为止,然后把该字 符之前的字符串转换成数字。不过,对于这个方法来说,第一个出现的小数点是有效字符。如果有两个小数点,第二个小数点将被看作无效的,parseFloat()方法会把这个小数点之前的字符串转换成数字。

parseFloat("1234blue"); // returns 1234.0
parseFloat("22.5"); // returns 22.5
parseFloat("22.34.5"); // returns 22.34
parseFloat("blue"); //returns NaN

显示转换

几乎每个数对象都提供了toString()函数将内容转换为字符串形式,其中Number提供的toString()函数可以将数字转换为字符串。

Number还提供了toFixed()函数将根据小数点后指定位数将数字转为字符串,四舍五入

// 将内容转换为字符串形式
var data = 10
console.log(data.toString())

// 根据小数点后指定位数将数字转为字符串,四舍五入
data = 1.4;
console.log(data.toFixed(0));
data = 1.49;
console.log(data.toFixed(1));

// 不能对null和undefined使用
data = null
console.log(data.toString())
data = undefined
console.log(data.toString())

JS 为 Number、Boolean、String 对象提供了构造方法,用于强制转换其他类型的数据。此时操作的是整个数据,而不是部分。

Number(false)       0
Number(true)         1
Number(undefined) NaN
Number(null)         0
Number( "5.5 ")     5.5
Number( "56 ")     56
Number( "5.6.7 ")   NaN
Number(new Object()) NaN
Number(100)         100

Boolean(""); // false – empty string
Boolean("hi"); // true – non-empty string
Boolean(100); // true – non-zero number
Boolean(null); // false - null
Boolean(0); // false - zero
Boolean(new Object()); // true – object

最后一种强制类型转换方法 String() 是最简单的,因为它可把任何值转换成字符串。要执行这种强制类型转换,只需要调用作为参数传递进来的值的 toString() 方法,即把 1 转换成"1 ",把 true转换成 "true ",把 false 转换成 "false ",依此类推。强制转换成字符串和调用 toString() 方法的唯一不同之处在于,对 null 或 undefined 值强制类型转换可以生成字符串而不引发错误:

var s1 = String(null); // "null"
var oNull = null;
var s2 = oNull.toString(); // won’t work, causes anerror

最为简单的一种转换为字符串的方式,直接在任意数据后面 + "" 即可。

运算符

运算符用于执行程序代码运算,会针对一个及其以上操作数来进行运算。

算数运算符

运算符

描述

例子

结果

+

x=y+2

x=7

-

x=y-2

x=3

*

x=y*2

x=10

/

x=y/2

x=2.5

%

求余数

x=y%2

x=1

++

自增(前导加、后导加)

x=++y

x=6

--

自减(前导减、后导减)

x=--y

x=4

赋值和扩展运算符

运算符

例子

等价于

结果

=

x=y

x=5

+=

x+=y

x=x+y

x=15

-=

x-=y

x=x-y

x=5

*=

x*=y

x=x*y

x=50

/=

x/=y

x=x/y

x=2

%=

x%=y

x=x%y

x=0

比较运算符

运算符

描述

例子

==

等于

x==8 为 false

===

全等(值和类型)

x===5 为 true;x==="5" 为 false

!=

不等于

x!=8 为 true

大于

x>8 为 false

<

小于

x<8 为 true

=

大于或等于

x>=8 为 false

<=

小于或等于

x<=8 为 true

逻辑运算符

运算符

描述

例子

&&

and

(x < 10 && y > 1) 为 true

||

or

(x==5 || y==5) 为 false

!

not

!(x==y) 为 true

三目运算符

运算符

描述

例子

?:

如果…否则…

3>5?3:5

控制语句

我们写的 JavaScript 代码都是按照从上到下依次执行,很多时候我们希望代码按照我们的意愿去执行,比如有选择性地执行某些代码,或者重复地执行某些代码,这就需要使用到流程控制语句。

流程控制语句一共有三种:

  1. 流程执行:从上到下,从左到右
  2. 选择执行:分支选择
  3. 循环执行:重复执行

选择

单选择

if (条件){
语句体;
}

首先执行条件

如果结果为true,则执行语句体;

如果结果为false,则结束if语句。

注意:若语句体只有一条语句,可以省略大括号,但不建议省略

双选择

if (条件){
语句体1;
}else {
语句体2;
}

首先执行条件

如果结果为true,则执行语句体1;

如果结果为false,则执行语句体2。

多选择

if(比较表达式1) {
语句体1;
}else if(比较表达式2){
语句体2;
}else if(比较表达式3){
语句体3;
}
...
[else {
语句体n+1;
}]

switch结构

多个 if ...else 且值为定值时(即=== 在比较运行结果时,采用的是严格相等运算符(===),而不是相等运算符(==),这意味着比较时不会发生类型转换。) ,可以使用 switch 替换:

switch(表达式) {
case 值1:
语句体1;
break;
case 值2:
语句体2;
break;
...
default:
语句体n+1;
[break;]
}

break 防止穿透,如果没有 break,则继续执行后面的代码,直到遇到 break 或全部执行完毕,但是有些时候会利用穿透。

循环

循环结构用于重复执行某个操作 简单理解就是重复执行同类型的代码,它有多种形式。

while

先判断后执行

基本格式
while(判断条件语句) {
循环体语句;
}

扩展格式:
初始化语句;
while(判断条件语句){
循环体语句;
控制条件语句; //   少了它很容易形成死循环
}

do...while

先执行后判断,至少执行一次

基本格式
do {
循环体语句;
}while(判断条件语句);

扩展格式:
初始化语句;
do {
循环体语句;
控制条件语句;
} while(判断条件语句);

for

for(初始化语句;判断条件语句;控制条件语句){
循环体语句;
}

死循环

条件永远成立,永远为 true,则会产生死循环,下面是最简单的死循环

while(true){}
for(;;){}

break 与 continue

break: 停止本层循环

continue:暂停本次循环,继续下一次

数组

数组是按次序排列的一组数据,每个值的位置都有编号(从0开始),整个数组用方括号表示。

数组定义

JS 中定义数组的三种方式如下(也可先声明再赋值):

var arr = [值1,值2,值3];  // 隐式创建

var arr = new Array(值1,值2,值3); // 直接实例化

var arr = new Array(size); // 创建数组并指定长度

基本操作

数组的长度可以通过length属性来获取,并可以任意更改

数组名.length
数组名.length = 新长度

数组中的每一个元素都可以被访问和修改,甚至是不存在的元素,无所谓越界

数组名[下标]
数组名[下标] = 新值

数组遍历

数组的遍历即依次访问数组的每一个元素 ,JS提供三种遍历数组的方式:

普通的for循环遍历

for(var i=0; i<=数组.length-1; i++){

}
如:
for(var idx=0;idx<arr.length;idx++){
console.log(arr[idx]);
}

for ... in

for(var 下标(名称任意) in 数组名){
数组名[下标]是获取元素
} // 下标(名称任意)
如:
for(var idx in arr){
console.log(arr[idx]);
}

forEach

数组名.forEach(function(element,index){
// element(名称任意):元素,index(名称任意):下标
})
如:
arr.forEach(function(elem,idx){
console.log(idx + "-->" + elem);
});

了解

数组在使用的时候建议大家规矩来用。在存放数据时,从下标0开始顺序的存放数组元素。
如果下标:
1.为非负整数(包括整数字符串):自动从0开始,不存在添加 undefined
2.为负数、小数、非数字符串:这些内容不计算在长度内,当成"属性"处理,相当于自定义属性。

数组非常灵活,使用数组元素
1.下标: 非负整数(包括整数字符串):
数组.下标
数组[下标]
2.下标:负数、小数、非数字字符串:
数组[属性]

  • for --> 不遍历属性
  • foreach -->不遍历属性和索引中的undefined
  • for in -->不遍历索引中的undefined

数组提供的操作方法

Array对象为我们提供了一些方法,可以很方便地操作数组

push          添加元素到最后
unshift       添加元素到最前
pop           删除最后一项
shift         删除第一项
reverse       数组翻转
join          数组转成字符串
indexOf       数组元素索引
slice         截取(切片)数组,原数组不发生变化
splice        剪接数组,原数组变化,可以实现前后删除效果
concat        数组合并

var arr = ['1','a',5,'3'];
console.log(arr);
arr.push(10);
console.log(arr);
arr.unshift('b');
console.log(arr);
arr.pop();
console.log(arr);
arr.shift();
console.log(arr);
arr.reverse();
console.log(arr);
console.log(arr.join('''));
console.log(arr);
console.log(arr.indexOf('a'));
console.log(arr.slice(2,5));
console.log(arr);
arr.splice(1,1,'一','二');
console.log(arr);
var arr1 = [0,'100'];
console.log(arr.concat(arr1));
console.log(arr);
console.log(arr1);
console.log(arr1.(arr));

函数

函数,即方法。就是一段预先设置的功能代码块,可以反复调用,根据输入参数的不同,返回不同的值。函数也是对象。

函数的定义

有三种函数定义的方式:函数声明语句、函数定义表达式、Function构造函数

函数声明语句

function 函数名([参数列表]){

}
例如:
function foo(){
console.log(1);
}
foo();

该种方式定义的函数具有声明提升的效果

foo();
function foo(){
console.log(1);
}
// 变量声明提升
console.log( a );
var a = 2;

函数定义表达式

以表达式方式定义的函数,函数的名称是可以不需要的

var 变量名 = function ([参数列表]) {

}
变量名();
例如:
var fun = function(){
console.log("Hello");
}
fun();

这种写法将一个匿名函数赋值给变量。这时,这个匿名函数又称函数表达式,因为赋值语句的等号右侧只能放表达式。

Function构造函数

Function构造函数接收任意数量的参数,但最后一个参数始终都被看成是函数体,而前面的参数则列举出了新函数的参数。

var add = new Function('x','y','return (x + y)');
// 等同于
function add(x, y) {
return (x + y);
}
add();

注意:

  1. js中的函数没有重载,同名的函数,会被后面的函数覆盖。
  2. js中允许有不定数目的参数,后面介绍arguments对象

函数的参数、调用和return语句

参数

函数运行的时候,有时需要提供外部数据,不同的外部数据会得到不同的结果,这种外部数据就叫参数,定义时的参数称为形参,调用时的参数称为实参

  • 实参可以省略,那么对应形参为undefined
  • 若函数形参同名(一般不会这么干):在使用时以最后一个值为准。
  • 可以给参数默认值:当参数为特殊值时,可以赋予默认值。
  • 参数为值传递,传递副本 ;引用传递时传递地址,操作的是同一个对象。

// 调用函数时,实参可以省略,则对应形参为undefined
function add(a , b) {
console.log(a + "+" + b + "=" + (a + b));
}
add(3,4,5)//3+4=7
add(1);//1+undefined=NaN
add();//undefined+undefined=NaN

// 若函数形参同名(一般不会这么干):在使用时以最后一个值为准
function add2(a , a) {
console.log(a);
}
add2(1,2);

// 给参数默认值
function defaultValue(a){
a = a || "a";
return a;
}
console.log(defaultValue());
function f(a){
//若参数a不为undefined或null,则取本身的值,否则给一个默认值
(a !== undefined && a !== null) ? a = a : a = 1;
return a;
}
console.log(f());

// 值传递
var num = 12;
function change(n) {
n = 30;
}
change(num);
console.log(num);
// 引用传递
var obj = {name: "tom"};
function paramter(o) {
o.name = 2;
}
paramter(obj);
console.log(obj.name);
// 给形参o赋予了新的数组
var obj2 = [1, 2, 3];
function paramter2(o){
o = [2, 3, 4];
o[1] = 3;
}
paramter2 (obj2);
console.log(obj2)

函数的调用

1. 常用调用方式

函数名([实参]);

存在返回值可以变量接收,若接收无返回值函数则为undefined。

2. 函数调用模式

function add(a,b){
return a+b;
}
var sum = add(1,2)
console.log(sum);

3. 方法调用模式

var o = {
m: function(){
console.log(1);
}
};
o.m();

return

函数的执行可能会有返回值,需要使用return语句将结果返回。return 语句不是必需的,如果没有的话,该函数就不返回任何值,或者说返回 undefined。

作用:

  1. 在没有返回值的方法中,用来结束方法。
  2. 有返回值的方法中,一个是用来结束方法,一个是将值带给调用者。

函数的作用域

函数作用域:全局 (global variable) 和 局部 (local variable)

1. 全局变量与局部变量同名问题

var box =1; // 全局变量
function display(box){
var box = 3; // 此处box与全局变量box没有关系,这里的box为传递的参数,相当于新声明的局部变量
var b = 2; // 局部变量
console.log("box-->" + box);
}
display();
// b 不能访问
console.log("b-->" + b);

2. 在函数中定义变量时,若没有加var关键字,使用之后自动变为全局变量

function fun(){
a = 100;
}
fun();
alert(a);

内置对象

Arguments   只在函数内部定义,保存了函数的实参
Array             数组对象
Date              日期对象,用来创建和获取日期
Math             数学对象
String             字符串对象,提供对字符串的一系列操作

String

◦ charAt(idx)   返回指定位置处的字符
◦ indexOf(Chr)   返回指定子字符串的位置,从左到右。找不到返回-1
◦ substr(m,n)   返回给定字符串中从m位置开始,取n个字符,如果参数n省略,则意味着取到字符串末尾。
◦ substring(m,n)   返回给定字符串中从m位置开始,到n位置结束,如果参数n省略,则意味着取到字符串末尾。
◦ toLowerCase()   将字符串中的字符全部转化成小写。
◦ toUpperCase()   将字符串中的字符全部转化成大写。
◦ length   属性,不是方法,返回字符串的长度。

Math

◦ Math.random()   随机数
◦ Math.ceil()   向上取整,大于最大整数
◦ Math.floor()   向小取整,小于最小整数String

Date

// 获取日期
◦ getFullYear()   年
◦ getMonth()   月
◦ getDate()   日
◦ getHours()   时
◦ getMinutes()   分
◦ getSeconds()   秒
// 设置日期
◦ setYear()
◦ setMonth()
◦ setDate()
◦ setHours()
◦ setMinutes()
◦ setSeconds()
◦ toLoacaleString() 转换成本地时间字符串

说明:

  1. getMonth():得到的值:0~11(1月~12月)
  2. setMonth():设置值时0~11
  3. toLocaleString():可根据本地时间把 Date 对象转换为字符串,并返回结果。

对象

对象(object)是 JavaScript 的核心概念,也是最重要的数据类型。JavaScript 的所有数据都可以被视为对象。JavaScript 提供多个内建对象,比如 String、Date、Array 等等。对象是带有属性和方法的特殊数据类型。

简单说,所谓对象,就是一种无序的数据集合,由若干个“键值对”(key-value)构成。通过JavaScript我们可以创建自己的对象。 JavaScript对象满足的这种”键值对”的格式我们称为JSON格式,以后会见得非常多,即伟大的JSON对象。

{键:值, 键2:值2,...}

对象的创建

JS 创建自定义对象,主要通过三种方式:字面量形式创建对象、通过new Object对象创建 、通过Object对象的create方法创建对象。

字面量形式创建

var 对象名 = {};//创建一个空的对象
var 对象名 = {键:值,键2:值2,...}

var obj = {
'name' : 'hello',
age : 12,
sayHello : function () {
console.log("我是对象中的方法");
},
courses : {
javase : 4,
javascript : 3
},
isLike : true,
members : [
{name : "小红",age : 20},
{name : "小绿",age : 22},
{name : "小蓝",age : 27},
{name : "小黄"}
]
};

通过new Object创建

var 对象名 = new Object(); // 创建一个空的对象

var obj = new Object();
obj.name = 'zs';
obj.age = 18;
console.log(obj);

通过Object对象的create方法创建

var 对象名 = Object.create(null);
var obj = Object.create(null);
obj.name = 'ls';
obj.gender = true
console.log(obj);

var objn = Object.create(obj);
objn.age = 18;
console.log(objn);
console.log(objn.gender)

对象的序列化和反序列化

序列化即将JS对象序列化为字符串,反序列化即将字符串反序列化为JS对象。JS中通过调用JSON方法,可以将对象序列化成字符串,也可以将字符串反序列化成对象 。

// 序列化对象,将对象转为字符串
JSON.stringify(object);

// 反序列化,将一个Json字符串转换为对象。
JSON.parse(jsonStr);

this

this是JavaScript语言的一个关键字。

它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。

随着函数使用场合的不同,this的值会发生变化。但是有一个总的原则,那就是this指的是,调用函数的那个对象。

在函数中使用this

在函数中使用this属于全局性调用,代表全局对象,通过window对象来访问。

function test () {
this.x = 1;
console.log(this.x);
}
test();
console.log(x); // 相当于定义在全局对象上的属性

var x = 10;
console.log(x)  // 10
function test (){
console.log(this.x)  // 10
this.x = 1;
console.log(this.x) // 1
console.log(this)
}

test();
console.log(x); // 1
console.log(this);

在对象中使用this

在对象中的函数使用this,代表当前的上级对象。

var obj = {
name : '张三',
age : 20,
sayHello : function () {
console.log(this.name)
console.log(this)
}
}
obj.sayHello();

查看原文

赞 0 收藏 0 评论 0

爱编程的小叮当 发布了文章 · 1月20日

FreeMarker 概述

FreeMarker 概述

FreeMarker概念

FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 是一个Java类库。

FreeMarker 被设计用来生成 HTML Web 页面,特别是基于 MVC 模式的应用程序,将视图从业务逻辑中抽离处理,业务中不再包括视图的展示,而是将视图交给 FreeMarker 来输出。虽然 FreeMarker 具有一些编程的能力,但通常由 Java 程序准备要显示的数据,由 FreeMarker 生成页面,通过模板显示准备的数据(如下图):

FreeMarker不是一个Web应用框架,而适合作为Web应用框架一个组件。

FreeMarker与容器无关,因为它并不知道HTTP或Servlet。FreeMarker同样可以应用

于非Web应用程序环境。

FreeMarker更适合作为Model2框架(如Struts)的视图组件,你也可以在模板中使用

JSP标记库。

FreeMarker特性

通用目标

能够生成各种文本:HTML、XML、RTF、Java 源代码等等

易于嵌入到你的产品中:轻量级;不需要 Servlet 环境

插件式模板载入器:可以从任何源载入模板,如本地文件、数据库等等

你可以按你所需生成文本:保存到本地文件;作为 Email 发送;从 Web 应用程序发送它返回给 Web 浏览器

强大的模板语言

所有常用的指令:include、if/elseif/else、循环结构

在模板中创建和改变变量

几乎在任何地方都可以使用复杂表达式来指定值

命名的宏,可以具有位置参数和嵌套内容

名字空间有助于建立和维护可重用的宏库,或将大工程分成模块,而不必担心名字冲突

输出转换块:在嵌套模板片段生成输出时,转换HTML转义、压缩、语法高亮等等;你可以定义自己的转换

通用数据模型

FreeMarker不是直接反射到Java对象,Java对象通过插件式对象封装,以变量方式在模板中显示

你可以使用抽象(接口)方式表示对象(JavaBean、XML文档、SQL查询结果集等等),告诉模板开发者使用方法,使其不受技术细节的打扰

为Web准备

在模板语言中内建处理典型Web相关任务(如HTML转义)的结构

能够集成到Model2 Web应用框架中作为JSP的替代

支持JSP标记库

为MVC模式设计:分离可视化设计和应用程序逻辑;分离页面设计员和程序员

智能的国际化和本地化

字符集智能化(内部使用UNICODE)

数字格式本地化敏感

日期和时间格式本地化敏感

非US字符集可以用作标识(如变量名)

多种不同语言的相同模板

强大的XML处理能力

<#recurse> 和 <#visit> 指令(2.3版本)用于递归遍历XML树。在模板中清楚和直接的访问XML对象模型。开源论坛 JForum 就是使用了 FreeMarker 做为页面模板。

FreeMarker环境搭建

新建 Maven Web项目

配置坐标依赖和部署插件

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/m...d">
<modelVersion>4.0.0</modelVersion>

<groupId>com.xxxx</groupId>
<artifactId>freemarker</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<name>freemarker Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
<!-- freemarker的坐标依赖 -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.23</version>
</dependency>
<!-- servlet-api的坐标依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
</dependency>

</dependencies>

<build>
<finalName>freemarker</finalName>
<!--
插件地址:
Tomcat
http://tomcat.apache.org/mave...
Jetty
https://www.eclipse.org/jetty...
-->
<plugins>
<!-- 配置jetty插件 -->
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.2.1.v20140609</version>
</plugin>
</plugins>

</build>
</project>

修改配置文件 web.xml

在项目的webapp/WEB-INF目录下的web.xml文件中,添加freemarker 相关 servlet 配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/ja...d">
<!-- FreeMarker 的Servlet配置 -->
<servlet>
<servlet-name>freemarker</servlet-name>
<servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class>
<init-param>
<!-- 模板路径 -->
<param-name>TemplatePath</param-name>
<!-- 默认在webapp目录下查找对应的模板文件 -->
<param-value>/</param-value>
</init-param>
<init-param>
<!-- 模板默认的编码:UTF-8 -->
<param-name>default_encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</servlet>
<!-- 处理所有以.ftl结尾的文件;ftl是freemarker默认的文件后缀 -->
<servlet-mapping>
<servlet-name>freemarker</servlet-name>
<url-pattern>*.ftl</url-pattern>
</servlet-mapping>
</web-app>

编写Servlet类

package com.xxxx.controllter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/f01")
public class FreeMarker01 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 添加数据
request.setAttribute("msg","Hello FreeMarker!");
// 请求转发跳转到ftl文件中
request.getRequestDispatcher("template/f01.ftl").forward(request,response);
}
}

新建模板文件 ftl

在webapp目录下新建template文件夹,创建f01.ftl文件

启动项目

访问项目

浏览器地址栏输入:http://localhost:8989/f01

FreeMarker 数据类型

Freemarker 模板中的数据类型由如下几种:

  • 布尔型:等价于 Java 的 Boolean 类型,不同的是不能直接输出,可转换为字符串输出
  • 日期型:等价于 java 的 Date 类型,不同的是不能直接输出,需要转换成字符串再输出
  • 数值型:等价于 java 中的 int,float,double 等数值类型

    有三种显示形式:数值型(默认)、货币型、百分比型

  • 字符型:等价于 java 中的字符串,有很多内置函数
  • sequence 类型:等价于 java 中的数组,list,set 等集合类型
  • hash 类型:等价于 java 中的 Map 类型

布尔类型

  1. 在Servlet中设置布尔类型的数据

    // 布尔类型
    request.setAttribute("flag", true);

  2. 获取数据

    <#--
    数据类型:布尔类型
    在freemarker中布尔类型不能直接输出;如果输出要先转成字符串
    方式一:?c
    方式二:?string 或 ?string("true时的文本","false时的文本")
    -->
    ${flag?c}

    ${flag?string}

    ${flag?string("yes","no")}

日期类型

  1. 在Servlet中设置日期类型的数据

    // 日期类型
    request.setAttribute("createDate",new Date());

  2. 获取数据

    <#--
    数据类型:日期类型
    在freemarker中日期类型不能直接输出;如果输出要先转成日期型或字符串

    1. 年月日          ?date
    2. 时分秒          ?time
    3. 年月日时分秒     ?datetime
    4. 指定格式        ?string("自定义格式")

    y:年  M:月  d:日
    H:时  m:分  s:秒
    -->
    <#-- 输出日期格式 -->
    ${createDate?date}

    <#-- 输出时间格式 -->
    ${createDate?time}

    <#-- 输出日期时间格式 -->
    ${createDate?datetime}

    <#-- 输出格式化日期格式 -->
    ${createDate?string("yyyy年MM月dd日 HH:mm:ss")}

数值类型

  1. 在Servlet设置数值型的数据

    // 数值类型
    request.setAttribute("age",18); // 数值型
    request.setAttribute("salary",10000); // 数值型
    request.setAttribute("avg",0.545); // 浮点型

  2. 获取数据

    <#--
    数据类型:数值类型
    在freemarker中数值类型可以直接输出;

    1. 转字符串

    普通字符串       ?c
    货币型字符串     ?string.currency
    百分比型字符串   ?string.percent

    1. 保留浮点型数值指定小数位(#表示一个小数位)

    ?string["0.##"]
    -->
    <#-- 直接输出数值型 -->
    ${age}

    ${salary}

    <#-- 将数值转换成字符串输出 -->
    ${salary?c}

    <#-- 将数值转换成货币类型的字符串输出 -->
    ${salary?string.currency}

    <#-- 将数值转换成百分比类型的字符串输出 -->
    ${avg?string.percent}

    <#-- 将浮点型数值保留指定小数位输出 (##表示保留两位小数) -->
    ${avg?string["0.##"]}

字符串类型

  1. 在Servlet中设置字符串类型的数据

    // 字符串类型
    request.setAttribute("msg","Hello ");
    request.setAttribute("msg2","freemarker");

  2. 获取数据

    <#--
    数据类型:字符串类型
    在freemarker中字符串类型可以直接输出;

    1. 截取字符串(左闭右开) ?substring(start,end)
    2. 首字母小写输出  ?uncap_first
    3. 首字母大写输出  ?cap_first
    4. 字母转小写输出  ?lower_case
    5. 字母转大写输出  ?upper_case
    6. 获取字符串长度  ?length
    7. 是否以指定字符开头(boolean类型) ?starts_with("xx")?string
    8. 是否以指定字符结尾(boolean类型) ?ends_with("xx")?string
    9. 获取指定字符的索引  ?index_of("xx")
    10. 去除字符串前后空格 ?trim
    11. 替换指定字符串  ?replace("xx","xx")

    -->
    <#-- 直接输出 -->
    ${msg} - ${msg2}

    ${msg?string} - ${msg2?string}

    <#-- 1. 截取字符串(左闭右开) ?substring(start,end) -->
    ${msg2?substring(1,4)}

    <#-- 2. 首字母小写输出  ?uncap_first -->
    ${msg?uncap_first}

    <#-- 3. 首字母大写输出  ?cap_first -->
    ${msg2?cap_first}

    <#-- 4. 字母转小写输出  ?lower_case -->
    ${msg?lower_case}

    <#-- 5. 字母转大写输出  ?upper_case -->
    ${msg?upper_case}

    <#-- 6. 获取字符串长度  ?length -->
    ${msg?length}

    <#-- 7. 是否以指定字符开头(boolean类型) ?starts_with("xx")?string -->
    ${msg?starts_with("H")?string}

    <#-- 8. 是否以指定字符结尾(boolean类型) ?ends_with("xx")?string -->
    ${msg?ends_with("h")?string}

    <#-- 9. 获取指定字符的索引  ?index_of("xxx") -->
    ${msg?index_of("e")}

    <#-- 10. 去除字符串前后空格 ?trim -->
    ${msg?trim?length}

    <#-- 11. 替换指定字符串  ?replace("xx","xxx") -->
    ${msg?replace("o","a")}

字符串空值情况处理

FreeMarker 的变量必须赋值,否则就会抛出异常。而对于 FreeMarker 来说,null 值和不存在的变量是完全一样的,因为 FreeMarker 无法理解 null 值。

FreeMarker 提供两个运算符来避免空值:

① ! :指定缺失变量的默认值

${value!}:如果value值为空,则默认值是空字符串

${value!"默认值"}:如果value值为空,则默认值是字符串"默认值"

② ?? :判断变量是否存在

如果变量存在,返回 true,否则返回 false

${(value??)?string}

<#-- 如果值不存在,直接输出会报错 -->
<#--${str}-->
<#-- 使用!,当值不存在时,默认显示空字符串 -->
${str!}

<#-- 使用!"xx",当值不存在时,默认显示指定字符串 -->
${str!"这是一个默认值"}

<#-- 使用??,判断字符串是否为空;返回布尔类型。如果想要输出,需要将布尔类型转换成字符串 -->
${(str??)?string}

sequence 类型

  1. 在Servlet中设置序列类型的数据

    // 序列类型 (数组、List、Set)
    // 数组操作
    String[] stars = new String[]{"周杰伦","林俊杰","陈奕迅","五月天"};
    request.setAttribute("stars",stars);

    // List操作
    List<String> citys = Arrays.asList("上海","北京","杭州","深圳");
    request.setAttribute("cityList",citys);

    // JavaBean集合
    List<User> userList = new ArrayList<>();
    userList.add(new User(1,"zhangsan",22));
    userList.add(new User(2,"lisi",18));
    userList.add(new User(3,"wangwu",20));
    request.setAttribute("userList",userList);

  2. 获取数据

    <#--
    数据类型:序列类型 (数组、List、Set)
    通过list指令输出序列
    <#list 序列名 as 元素名>
    ${名称}
    </#list>
    获取序列的长度       ${序列名?size}
    获取序列元素的下标     ${元素名?index}
    获取第一个元素       ${序列名?first}
    获取最后一个元素     ${序列名?last}

    倒序输出   序列名?reverse
    升序输出   序列名?sort
    降序输出   序列名?sort?reverse
    指定字段名排序    序列名?sort_by("字段名")
    注:一般是JavaBean集合,对应的字段名需要提供get方法
    -->
    <#-- 数组操作 -->
    <#list stars as star>
    下标:${star?index} -- 名字:${star}

    </#list>
    数组的长度:${stars?size}  

    <#-- 获取第一个元素 -->
    第一个元素:${stars?first}

    <#-- 获取最后一个元素 -->
    最后一个元素:${stars?last}




    <#-- List操作 -->
    <#list cityList as city >
    ${city}

    </#list>
    List的size:${cityList?size}

    <#-- 倒序输出 -->
    <#list cityList?reverse as city >
    ${city} -
    </#list>



    <#-- 升序输出 -->
    <#list cityList?sort as city >
    ${city} -
    </#list>


    <#-- 降序输出 -->
    <#list cityList?sort?reverse as city >
    ${city} -
    </#list>



    <#-- JavaBean集合 -->
    <#list userList as user>
    编号:${user.userId}  
    姓名:${user.uname}  
    年龄:${user.uage}  


    </#list>

    <#-- 按照指定字段名排序 -->
    <#list userList?sort_by("uage") as user>
    ${user.uname} |
    </#list>

hash 类型

  1. 在Servlet中设置hash类型的数据

    // Map操作
    Map<String,String> cityMap = new HashMap<>();
    cityMap.put("sh","上海");
    cityMap.put("bj","北京");
    cityMap.put("sz","深圳");
    request.setAttribute("cityMap",cityMap);

  2. 获取数据

    <#--
    数据类型:hash类型
    key遍历输出
    <#list hash?keys as key>
    ${key} -- ${hash[key]}
    </#list>
    value遍历输出
    <#list hash?values as value>
    ${value}
    </#list>
    -->
    <#-- key遍历输出 -->
    <#list cityMap?keys as key>
    ${key} -- ${cityMap[key]}

    </#list>

    <#-- value遍历输出 -->
    <#list cityMap?values as value>
    ${value} |
    </#list>

FreeMarker 常见指令

assign 自定义变量指令

使用 assign 指令你可以创建一个新的变量, 或者替换一个已经存在的变量。

<#--
assign 自定义变量指令
语法:
<#assign 变量名=值>
<#assign 变量名=值 变量名=值> (定义多个变量)
-->
<#assign str="hello">
${str}

<#assign num=1 names=["zhangsan","lisi","wangwu"] >
${num} -- ${names?join(",")}

if elseif else 逻辑判断指令

可以使用 ifelseifelse 指令来条件判断是否满足某些条件。

<#--
if, else, elseif 逻辑判断指令
格式:
<#if condition>
...
<#elseif condition2>
...
<#elseif condition3>
...
<#else>
...
</#if>
注:

  1. condition, condition2等:将被计算成布尔值的表达式。
  2. elseif 和 else 指令 是可选的。

-->
<#assign score = 80>
<#if score < 60>
你个小渣渣!
<#elseif score == 60>
分不在高,及格就行!
<#elseif score gt 60 && score lt 80>
哎哟不错哦!
<#else>
你很棒棒哦!
</#if>



<#-- 判断数据是否存在 -->
<#assign list="">
<#if list??>
数据存在
<#else>
数据不存在
</#if>

list 遍历指令

可以使用 list 指令来对序列进行遍历。

<#--
list指令
格式1:
<#list sequence as item>

</#list>
格式2:
<#list sequence as item>

<#else>
当没有选项时,执行else指令
</#list>
注:

  1. else 部分是可选的
  2. sequence: 想要迭代的项,可以是序列或集合的表达式
  3. item: 循环变量 的名称
  4. 当没有迭代项时,才使用 else 指令, 可以输出一些特殊的内容而不只是空在那里

-->
<#assign users = ["张三","李四","王五"]>
<#-- 遍历序列 -->
<#list users as user>
${user}
</#list>



<#--判断数据不为空,再执行遍历 (如果序列不存在,直接遍历会报错)-->
<#if users2??>
<#list users2 as user>
${user}
</#list>
</#if>



<#assign users3 = []>
<#-- 当序列没有数据项时,使用默认信息 -->
<#list users3 as user>
${user}
<#else>
当前没有数据!
</#list>

macro 自定义指令

可以使用 macro 指令来自定义一些自定义指令。

<#--
macro 自定义指令 (宏)

  1. 基本使用

格式:
<#macro 指令名>
指令内容
</#macro>
使用:
<@指令名></@指令名>

  1. 有参数的自定义指令

格式:
<#macro 指令名 参数名1 参数名2>
指令内容
</#macro>
使用:
<@指令名 参数名1=参数值1 参数名2=参数值2></@指令名>

注:

  1. 指令可以被多次使用。
  2. 自定义指令中可以包含字符串,也可包含内置指令

-->
<#-- 定义基本的自定义指令 -->
<#macro address>
© 1999–2015 The FreeMarker Project. All rights reserved.
</#macro>
<#-- 使用指令 -->
<@address></@address>

<@address></@address>




<#-- 定义有参数的自定义指令 -->
<#macro queryUserByName uname>
通过用户名查询用户信息 - ${uname}
</#macro>
<#-- 使用指令,并传递参数 -->
<@queryUserByName uname="admin"></@queryUserByName>


<#-- 定义有多个参数的自定义指令 -->
<#macro queryUserByParams uname uage>
通过多个餐宿查询用户信息 - ${uname} - ${uage}
</#macro>
<#-- 使用指令,并传递多个参数 -->
<@queryUserByParams uname="admin" uage=18></@queryUserByParams>




<#-- 自定义指令中包含内置指令 -->
<#macro cfb>
<#list 1..9 as i>
<#list 1..i as j>
${j}*${i}=${j*i} 
</#list>


</#list>
</#macro>
<@cfb></@cfb>
<@cfb></@cfb>

<#-- 动态数据 -->
<#macro cfb2 num>
<#list 1..num as i>
<#list 1..i as j>
${j}*${i}=${j*i} 
</#list>


</#list>
</#macro>
<@cfb2 num=5></@cfb2>

nested 占位指令

nested 指令执行自定义指令开始和结束标签中间的模板片段。嵌套的片段可以包含模板中任意合法的内容。

<#--
nested 占位指令
nested 相当于占位符,一般结合macro指令一起使用。
可以将自定义指令中的内容通过nested指令占位,当使用自定义指令时,会将占位内容显示。
-->
<#macro test>
这是一段文本!
<#nested>
<#nested>
</#macro>
<@test><h4>这是文本后面的内容!</h4></@test>

import 导入指令

import 指令可以引入一个库。也就是说,它创建一个新的命名空间, 然后在那个命名空间中执行给定路径的模板。可以使用引入的空间中的指令。

commons.ftl

<#macro cfb>
<#list 1..9 as i>
<#list 1..i as j>
${j}*${i}=${j*i} 
</#list>


</#list>
</#macro>

在其他ftl页面中通过import导入commons.ftl的命名空间,使用该命名空间中的指令

test.ftl

<#-- 导入命名空间 -->
<#import "commons.ftl" as common>
<#-- 使用命名空间中的指令 -->
<@common.cfb></@common.cfb>

include 包含指令

可以使用 include 指令在你的模板中插入另外一个 FreeMarker 模板文件 。 被包含模板的输出格式是在 include 标签出现的位置插入的。 被包含的文件和包含它的模板共享变量,就像是被复制粘贴进去的一样。

<#--包含指令(引入其他页面文件) include-->
<#--html文件-->
<#include "test.html">

<#--freemarker文件-->
<#include "test.ftl">

<#--text文件-->
<#include "test.txt">

FreeMarker 页面静态化

通过上述介绍可知 Freemarker 是一种基于模板的、用来生成输出文本的通用工具,所以 我们必须要定制符合自己业务的模板,然后生成自己的 html 页面。Freemarker 是通过 freemarker.template.Configuration 这个对象对模板进行加载的(它也处理创建和缓存预 解析模板的工作),然后我们通过 getTemplate 方法获得你想要的模板,有一点要记住 freemarker.template.Configuration 在你整个应用必须保证唯一实例。

定义模板

news.ftl

<#-- 新闻标题 -->
<h1>${title}</h1>
<p>
新闻来源:${source} &nbsp; 发布时间:${pubTime?sring("yyyy-MM-dd HH:mm")}
</p>
<#-- 新闻内容 -->
<p>
${content}
</p>

加载模板


@WebServlet("/news")
public class NewsServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 实例化模板配置对象
Configuration configuration = new Configuration();
// 设置加载模板的上下文 以及 设置加载模板路径(模板存放的路径)
configuration.setServletContextForTemplateLoading(getServletContext(),"/template");
// 设置模板的编码格式
configuration.setDefaultEncoding("UTF-8");
// 加载模板文件,获取模板对象
Template template = configuration.getTemplate("news.ftl");

// 设置模型数据
Map<String,Object> map = new HashMap<>();
map.put("title", "特别就业季:稳就业情况如何? 哪些问题待解?");
map.put("source", "人民日报");
map.put("pubTime", new Date());
map.put("content", "中共中央政治局常务委员会近日召开会议强调," +
"要有针对性地开展援企、稳岗、扩就业工作," +
"做好高校毕业生、农民工等重点群体就业工作," +
"积极帮助个体工商户纾困。疫情期间,稳就业情况如何?还有哪些问题待解?" +
"记者采访了不同群体,记录这个特别的就业季。");

// 获取项目所在的根目录
String basePath = request.getServletContext().getRealPath("/");
// 设置页面存放的目录
File htmlFile = new File(basePath + "/html");
// 判断目录是否存在
if (!htmlFile.exists()) {
// 如果目录不存在,则新建目录
htmlFile.mkdir();
}
// 获取文件名(随机生成不重复的文件名)
String fileName = System.currentTimeMillis() + ".html";
// 创建html文件
File file = new File(htmlFile, fileName);
// 获取文件输出流
FileWriter writer = new FileWriter(file);
try {
// 输出html 将模型数据填充到模板中
template.process(map, writer);
// 输出成功
System.out.println("新闻创建成功!");
} catch (TemplateException e) {
e.printStackTrace();
} finally {
writer.flush();
writer.close();
}
}
}

生成对应的html文件

浏览器地址栏输入:

http://localhost:8989/news

生成的文件存放在当前项目的webapp目录下的html目录中。

FreeMarker 运算符

算术运算符

<!--
算术运算
+、-、*、/、%
-->
<#assign a1 = 8 a2 = 2 >
${a1} + ${a2} = ${a1 + a2} <br/>
${a1} - ${a2} = ${a1 - a2} <br/>
${a1} * ${a2} = ${a1 * a2} <br/>
${a1} / ${a2} = ${a1 / a2} <br/>
${a1} % ${a2} = ${a1 % a2} <br/>
<!--字符串运算-->
${"hello" + "," + "freemarker"}

逻辑运算符

<#--
逻辑运算符
&&、||、!
-->

比较运算符

<#--
比较运算符

(gt): 大于号,推荐使用 gt
< (lt): 小于号,推荐使用 lt
= (gte): 大于等于, 推荐是用 gte
<= (lte): 小于等于,推荐使用 lte
== : 等于
!= : 不等于
-->

空值运算符

<#--
空值运算符

  1. ??:判断是否为空,返回布尔类型

如果不为空返回 false, 如果为空返回 true,不能直接输出
${(name??)?string}

  1. !: 设置默认值,如果为空,则设置默认值
  2. 设置默认为空字符串:

${name!}

  1. 设置指定默认值

${name!'zhangsan'}
-->

查看原文

赞 0 收藏 0 评论 0

爱编程的小叮当 发布了文章 · 1月19日

Python-爬虫实战练习

爬虫前期准备
01 爬虫就是模拟浏览器抓取东西,爬虫三部曲:数据爬取、数据解析、数据存储
数据爬取:手机端、pc端数据解析:正则表达式数据存储:存储到文件、存储到数据库

  1. 相关python库

爬虫需要两个库模块:requests和re

  1. requests库

requests是比较简单易用的HTTP库,相较于urllib会简洁很多,但由于是第三方库,所以需要安装,文末附上安装教程链接(链接全在后面,这样会比较方便看吧,贴心吧~)

requests库支持的HTTP特性:

保持活动和连接池、Cookie持久性会话、分段文件上传、分块请求等

Requests库中有许多方法,所有方法在底层的调用都是通过request()方法实现的,所以严格来说Requests库只有request()方法,但一般不会直接使用request()方法。以下介绍Requests库的7个主要的方法:

①requests.request()

构造一个请求,支撑一下请求的方法

具体形式:requests.request(method,url,**kwargs)

method:请求方式,对应get,post,put等方式

url:拟获取页面的url连接

**kwargs:控制访问参数

②requests.get()

获取网页HTM网页的主要方法,对应HTTP的GET。构造一个向服务器请求资源的Requests对象,返回一个包含服务器资源的Response对象。

Response对象的属性:

属性说明r.status_codeHTTP请求的返回状态(连接成功返回200;连接失败返回404)r.textHTTP响应内容的字符串形式,即:url对应的页面内容r.encoding从HTTP header中猜测的响应内容编码方式r.apparent_encoding从内容中分析出的响应内容编码方式(备选编码方式)r.contentHTTP响应内容的二进制形式

具体形式:res=requests.get(url)

code=res.text (text为文本形式;bin为二进制;json为json解析)

③requests.head()

获取HTML的网页头部信息,对应HTTP的HEAD

具体形式:res=requests.head(url)

④requests.post()

向网页提交post请求方法,对应HTTP的POST

具体形式:res=requests.post(url)

⑤requests.put()

向网页提交put请求方法,对应HTTP的PUT

⑥requests.patch()

向网页提交局部修改的请求,对应HTTP的PATCH

⑦requests.delete()

向网页提交删除的请求,对应HTTP的DELETE

"""requests 操作练习"""

import requests

import re

数据的爬取

h = {

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36'

}

response = requests.get('https://movie.douban.com/chart',headers=h)

html_str = response.text

数据解析

pattern = re.compile('') # .*? 任意匹配尽可能多的匹配尽可能少的字符

result = re.findall(pattern,html_str)

print(result)

  1. re正则表达式:(Regular Expression)

一组由字母和符号组成的特殊字符串,作用:从文本中找到你想要的格式的句子

关于 .*? 的解释:

  • 匹配前面的子表达式零次或多次。例如,zo能匹配“z”以及“zoo”。等价于{0,}。

? 匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串。例如,对于字符串“oooo”,“o+?”将匹配单个“o”,而“o+”将匹配所有“o”。

. 匹配除“n”之外的任何单个字符。要匹配包括“n”在内的任何字符,请使用像“(.

.* 具有贪婪的性质,首先匹配到不能匹配为止,根据后面的正则表达式,会进行回溯。

.*?则相反,一个匹配以后,就往下进行,所以不会进行回溯,具有最小匹配的性质(尽可能匹配少的字符但是要匹配出所有的字符)。

(.*) 是贪婪匹配代表尽可能多的匹配字符因此它将h和l之间所有的字符都匹配了出来

  1. xpath解析源码

import requests

import re

from bs4 import BeautifulSoup

from lxml import etree

数据爬取(一些HTTP头的信息)

h = {

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36'

}

response = requests.get('https://movie.XX.com/chart',headers=h)

html_str = response.text

数据解析

正则表达式解析

def re_parse(html_str):

pattern = re.compile('<a class="nbg".?title="(.?)"')

results = re.findall(pattern,html_str)

print(results)

return results

bs4解析

def bs4_parse(html_str):

soup = BeautifulSoup(html_str,'lxml')

items = soup.find_all(class_='nbg')

for item in items:

print(item.attrs['title'])

lxml解析

def lxml_parse(html_str):

html = etree.HTML(html_str)

results = html.xpath('//a[@class="nbg"]/@title')

print(results)

return results

re_parse(html_str)

bs4_parse(html_str)

lxml_parse(html_str)

  1. python写爬虫的架构

Python研究之爬虫练习
从图上可以看到,整个基础爬虫架构分为5大类:爬虫调度器、URL管理器、HTML下载器、HTML解析器、数据存储器。

下面给大家依次来介绍一下这5个大类的功能:

① 爬虫调度器:主要是配合调用其他四个模块,所谓调度就是去调用其他的模板。

② URL管理器:就是负责管理URL链接的,URL链接分为已经爬取的和未爬取的,这就需要URL管理器来管理它们,同时它也为获取新URL链接提供接口。

③ HTML下载器:就是将要爬取的页面的HTML下载下来。

④ HTML解析器:就是将要爬取的数据从HTML源码中获取出来,同时也将新的URL链接发送给URL管理器以及将处理后的数据发送给数据存储器。

⑤ 数据存储器:就是将HTML下载器发送过来的数据存储到本地。

whois爬取
每年,有成百上千万的个人、企业、组织和政府机构注册域名,每个注册人都必须提供身份识别信息和联系方式,包括姓名、地址、电子邮件、联系电话、管理联系人和技术联系人一这类信息通常被叫做whois数据

"""

whois

http://whois.chinaz.com/sina.com

"""

import requests

import re

h = {

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36'

}

response = requests.get('http://whois.chinaz.com/'+input("请输入网址:"),headers=h)

print(response.status_code)

html = response.text

print(html)

解析数据

pattern = re.compile('class="MoreInfo".?>(.?)</p>',re.S)

result = re.findall(pattern,html)

方法一:

str = re.sub('n',',',result[0])

print(str)

方法二:

print(result[0].replace('/n',','))

爬取电影信息
"""爬取*眼电影前100电影信息"""

import requests

import re

import time

count = [0,10,20,30,40,50,60,70,80,90]

h = {

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36'

}

responce = requests.get('https://XX.com/board/4?offset=0', headers=h)

responce.encoding = 'utf-8'

html = responce.text

解析数据 time.sleep(2)

patter = re.compile('class="name">.?title="(.?)".?主演:(.?)</p>.?上映时间:(.?)</p>', re.S)

time.sleep(2)

result = re.findall(patter, html)

print(result)

with open('maoyan.txt', 'a', encoding='utf-8') as f:

for item in result: # 读取result(以元组的形式储存)中的内容=》

for i in item:

f.write(i.strip().replace('n', ','))

print('n')

爬取图片
"""*精灵爬取练习 http://616pic.com/png/ ==》 http://XX.616pic.com/ys_img/0...g"""

import requests

import re

import time

数据的爬取img的url

def get_urls():

response = requests.get('http://XX.com/png/')

html_str = response.text

解析数据,得到url

pattern = re.compile('<img class="lazy" data-original="(.*?)"')

results = re.findall(pattern,html_str)

print(results)

return results

<img class="lazy" data-original="http://XX.616pic.com/ys_img/00/06/20/64dXxVfv6k.jpg">

下载图片

def down_load_img(urls):

for url in urls:

response = requests.get(url)

with open('temp/'+url.split('/')[-1], 'wb') as f:

f.write(response.content)

print(url.split('/')[-1],'已经下载成功')

if name == '__main__':

urls = get_urls()

爬取小仙女
'''头条美女爬取====方法一'''import requests

import re

url = 'https://www.XX.com/api/search...×tamp=1596180364628&_signature=-Bv0rgAgEBA-TE0juRclmfgatbAAKdC7s6ktYqc7u9jLqXOQ5SBCDkd25scxRvDydd6TgtOw0B7RVuaQxhwY1BwV89sPbdam8LkNuV08d0QfrZqQ4oOOrOukEJ1qxroigLT'

response = requests.get(url)

print(response.status_code)

html_str = response.text

解析"large_image_url":"(.*?)"

pattern = re.compile('"large_image_url":"(.*?)"')

urls = re.findall(pattern,html_str)

print(urls)def down_load(urls):

for url in urls:

response = requests.get(url)

with open('pic/'+url.split('/')[-1],'wb') as f:

f.write(response.content)

print(url.split('/')[-1],'已经下载成功')

if name == '__main__':

down_load(urls)

Python研究之爬虫练习
'''头条美女爬取====方法二'''import requests

import re

from urllib.parse import urlencode

https://www.XX.com/api/search... get_urls(page):

keys = {

'aid':'24',

'app_name':'web_search',

'offset':20*page,

'keyword':'美女',

'count':'20'

}

keys_word = urlencode(keys)

url = 'https://www.XX.com/api/search...'+keys_word

response = requests.get(url)

print(response.status_code)

html_str = response.text

解析"large_image_url":"(.*?)"

pattern = re.compile('"large_image_url":"(.*?)"',re.S)

urls = re.findall(pattern, html_str)

return urls#下载图片

def download_imags(urls):

for url in urls:

response = requests.get(url)

with open('pic/'+url.split('/')[-1]+'.jpg','wb') as f:

f.write(response.content)

print(url.split('/')[-1]+'.jpg',"已下载~~")if name == '__main__':

for page in range(3):

urls = get_urls(page)

print(urls)

download_imags(urls)

Python研究之爬虫练习
5 线程池
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。

"""线程池"""from concurrent.futures import ThreadPoolExecutor

import time

import threadingdef ban_zhuang(i):

print(threading.current_thread().name,"开始搬砖{}".format(i))

time.sleep(2)

print("员工{}搬砖完成一共搬砖:{}".format(i,12**2)) #将format里的内容输出到{}if name == '__main__': #主线程

start_time = time.time()

print(threading.current_thread().name,"开始搬砖")

with ThreadPoolExecutor(max_workers=5) as pool:

for i in range(10):

p = pool.submit(ban_zhuang,i)

end_time =time.time()

print("一共搬砖{}秒".format(end_time-start_time))

结合多线程的爬虫:

'''头条美女爬取'''import requests

import re

from urllib.parse import urlencode

import timeimport threading

https://www.XX.com/api/search... get_urls(page):

keys = {

'aid':'24',

'app_name':'web_search',

'offset':20*page,

'keyword':'美女',

'count':'20'

}

keys_word = urlencode(keys)

url = 'https://www.XX.com/api/search...'+keys_word

response = requests.get(url)

print(response.status_code)

html_str = response.text

解析"large_image_url":"(.*?)"

pattern = re.compile('"large_image_url":"(.*?)"',re.S)

urls = re.findall(pattern, html_str)

return urls#下载图片

def download_imags(urls):

for url in urls:

try:

response = requests.get(url)

with open('pic/'+url.split('/')[-1]+'.jpg','wb') as f:

f.write(response.content)

print(url.split('/')[-1]+'.jpg',"已下载~~")

except Exception as err:

print('An exception happened: ')

if name == '__main__':

start = time.time()

thread = []

for page in range(3):

urls = get_urls(page)

print(urls)

多线程

for url in urls:

th = threading.Thread(target=download_imags,args=(url,))

download_imags(urls)

thread.append(th)

for t in thread:

t.start()

for t in thread:

t.join()end = time.time()

print('耗时:',end-start)

6 tips--爬虫协议
Robots协议,又称作爬虫协议,机器人协议,全名叫做网络爬虫排除标准(Robots Exclusion Protocol),是用来告诉爬虫和搜索引擎哪些页面可以抓取,哪些不可以抓取,通常为一个robots.txt文本文件,一般放在网站的根目录下。

Robots协议:在网页的根目录+/robots.txt 如www.baidu.com/robots.txt

User-agent: Baiduspider
Disallow: /baidu
Disallow: /s?
Disallow: /ulink?
Disallow: /link?
Disallow: /home/news/data/
Disallow: /bh

User-agent: Googlebot
Disallow: /baidu
Disallow: /s?
Disallow: /shifen/
Disallow: /homepage/
Disallow: /cpro
Disallow: /ulink?
Disallow: /link?
Disallow: /home/news/data/
Disallow: /bh
tips:要遵守爬虫协议哟,呐。。只能用于爬着玩儿哈~记得挂代理~

7 相关链接
requests的安装与使用 https://www.jianshu.com/p/140...

re的使用说明 https://www.cnblogs.com/vmask...

其他的爬虫相关文章 https://blog.csdn.net/qq_2729...

爬虫的视频 https://www.imooc.com/learn/563

查看原文

赞 0 收藏 0 评论 0

爱编程的小叮当 发布了文章 · 1月19日

Windows10错误在打开特定路径时导致BSOD崩溃

Windows 10中的错误仅通过在浏览器的地址栏中打开特定路径或使用其他Windows命令,即可使操作系统崩溃并显示蓝屏死机。

上周,BleepingComputer了解到Windows安全研究人员在Twitter上披露的两个错误,攻击者可以在各种攻击中滥用这些错误。

第一个错误允许无特权的用户或程序输入单个命令,该命令导致NTFS卷被标记为已损坏。尽管chkdsk在许多测试中都解决了此问题,但我们的一项测试表明该命令导致硬盘驱动器损坏,从而导致Windows无法启动。

今天,我们看看导致Windows 10仅通过尝试打开一条异常路径而导致BSOD崩溃的第二个错误。

打开此路径会导致BSOD

自10月以来,Windows安全研究员 Jonas Lykkegaard 在推特上发表了很多次推文,讲述了一条路径,该路径会立即导致Windows 10崩溃并在进入Chrome地址栏中时显示BSOD。

当开发人员想要直接与Windows设备进行交互时,他们可以将Win32设备命名空间路径作为各种Windows编程功能的参数传递。例如,这允许应用程序直接与物理磁盘进行交互,而无需通过文件系统。

Lykkegaard告诉BleepingComputer,他发现了“控制台多路复用器驱动程序”的以下Win32设备名称空间路径,他认为该路径用于“内核/用户模式ipc”。当以各种方式打开路径时,即使来自低特权用户,也会导致Windows 10崩溃。

.globalrootdevicecondrvkernelconnect

连接到该设备时,开发人员应传递“ attach”扩展属性以与该设备正确通信。

CDCreateKernlConnection显示“附加”扩展属性

Lykkegaard发现,如果由于不正确的错误检查而尝试不通过属性而连接到路径,则会导致异常,从而导致Windows 10中的蓝屏死机(BSOD)崩溃。

更糟糕的是,特权低的Windows用户可以尝试使用此路径连接到设备,从而使计算机上执行的任何程序都很容易崩溃Windows 10。

在我们的测试中,我们已经确认此错误在Windows 10 1709版和更高版本中存在。BleepingComputer无法在早期版本中对其进行测试。

BleepingComputer上周与Microsoft联系,以了解他们是否已经知道该错误以及是否会修复该错误。

微软发言人对BleepingComputer表示:“微软对调查已报告的安全问题的客户承诺,我们将尽快为受影响的设备提供更新。”

威胁演员可以滥用该错误

尽管目前尚不确定此漏洞是否可用于远程代码执行或提升特权,但仍可以将其用作计算机上的拒绝服务攻击。

Lykkegaard与BleepingComputer共享了一个Windows URL文件(.url),其设置指向。 globalroot device condrv kernelconnect。下载文件后,Windows 10会尝试从有问题的路径中呈现URL文件的图标,并自动使Windows 10崩溃。

BSOD由访问。 globalroot device condrv kernelconnect引起

此后,BleepingComputer发现了许多其他利用此bug的方法,包括在Windows登录时自动导致BSOD的方法。

在现实生活中,该漏洞可能会被威胁角色滥用,他们可以访问网络并希望在攻击过程中掩盖自己的踪迹。

如果他们具有管理员凭据,则可以远程执行访问网络上所有Windows 10设备上的此路径的命令,以使它们崩溃。在网络上造成的破坏可能会延迟调查或阻止管理控件检测到特定计算机上的攻击。

查看原文

赞 0 收藏 0 评论 0

爱编程的小叮当 发布了文章 · 1月18日

服务器Tomcat,你会安装了吗?

Tomcat 是一个符合 JavaEE WEB 标准的最小的 WEB 容器,所有的 JSP 程序一定要有 WEB 容器的支持才能运行,而且在给定的 WEB 容器里面都会支持事务处理操作。

Tomcat 是由 Apache 提供的(www.apache.org),可以用安装版和解压版,安装版可以在服务中出现一 Tomcat 的服务,免安装没有,开发中使用免安装版。 Tomcat 简单的说就是一个运行 Java 的网络服务器,底层是 Socket 的一个程序,它也是 JSP 和 Servlet 的一个容器。Tomcat 是 Apache 软件基金会(Apache Software Foundation)的 Jakarta 项目中的一个核心项目,由 Apache、Sun和其他一些公司及个人共同开发而成。

由于有了 Sun 的参与和支持,最新的 Servlet 和 JSP 规范总是能在 Tomcat 中得到体现。因为 Tomcat 技术先进、性能稳定,而且免费,因而深受 Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的 Web 应用服务器

Tomcat 服务器是一个免费的开放源代码的 Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试 JSP 程序的首选。 对于一个初学者来说,可以这样认为,当在一台机器上配置好 Apache 服务器,可利用它响应 HTML(标准通用标记语言下的一个应用)页面的访问请求。实际上 Tomcat 部分是 Apache 服务器的扩展,但它是独立运行的,所以当你运行 tomcat 时,它实际上作为一个与 Apache 独立的进程单独运行的。

当配置正确时,Apache 为 HTML 页面服务,而 Tomcat 实际上是在运行 JSP 页面和 Servlet。另外,Tomcat 和 IIS 等 Web 服务器一样,具有处理 HTML 页面的功能,另外它还是一个 Servlet 和 JSP 容器,独立的 Servlet 容器是 Tomcat 的默认模式。不过,Tomcat 处理静态 HTML 的能力不如 Apache 服务器。目前 Tomcat 最新版本为 9.0。

Tomcat安装方式

  • 确保JDK环境配置正确
  • 官网下载Tomcat安装包
  • 解压安装包
  • 集成到编译工具

案例实操

运行 Tomcat 需要 JDK 的支持【Tomcat 会通过 JAVA_HOME 找到所需要的 JDK】。安装就是解压缩过程。启动 Tomcat,能访问则算安装好了

1、解压

2、ROOT 目录中查看 index.html 或 index.jsp 文件

Tomcat8 中自带了页面,而 tomcat7 免安装下没有,如果直接访问会出 404 Tomcat7.XXX 则需要查看 webapps->ROOT 目录中是否有 index.html 或者 index.jsp,如果没有则自己手动添加一个 html 文件或者到其他地方拷贝一份 jsp,此时能访问该页面则是配置成功。

3、启动 Tomcat (在 tomcat 的安装目录下的 bin 目录 使用命令行启动 tomcat)

启动后启动窗口不能关闭

4、打开浏览器输入 http://localhost:8080/ 访问

OK,Tomcat 安装成功。

5、关闭 Tomcat (在 tomcat 的安装目录下的 bin 目录 使用命令行关闭 tomcat)

扩展

Tomcat 目录结构

  1. bin:启动和关闭 tomcat 的 bat 文件
  2. conf:配置文件server.xml 该文件用于配置 server 相关的信息,比如 tomcat 启动的端口号,配置主机(Host) web.xml 文件配置与 web 应用(web 应用相当于一个 web 站点)tomcat-user.xml 配置用户名密码和相关权限.
  3. lib:该目录放置运行 tomcat 运行需要的 jar 包
  4. logs:存放日志,当我们需要查看日志的时候,可以查询信息
  5. webapps:放置我们的 web 应用
  6. work 工作目录:该目录用于存放 jsp 被访问后生成对应的 server 文件和 .class 文件

Eclipse 关联 Tomcat

Window→preferences→Server→Runtime Environment→add→apache-tomcat-8.0.23

查看原文

赞 0 收藏 0 评论 0

爱编程的小叮当 发布了文章 · 1月15日

Spring Ioc 实例化 Bean 对象有几种方式?

Spring 实例化 bean 的方式

  • 构造器的方式
  • 静态工厂方式
  • 实例化工厂方式

案例实操

构造器的方式实例化 bean 对象

<bean id="hello" name="hello" class="com.xxx.demo.Hello"></bean>

通过默认构造器创建 空构造方法必须存在 否则创建失败

静态工厂模式

特点:

要有该工厂类及工厂方法

工厂方法是静态的

StaticFactory 静态工厂

/**

  • 静态工厂模式

*
*/
public class StaticFactory {
public static GoodsService createGoodsService() {//方法一定要是一个静态方法
return new GoodsService();
}
}

GoodsService实体类

public class GoodsService {
public void getGoodsInfo() {
System.out.println("外星人贼便宜");
}
}

Bean配置

<bean id="goodsService"
class="com.xxx.demo.StaticFactory" factory-method="createGoodsService"></bean>

当我们指定Spring使用静态工厂方法来创建Bean实例时,Spring将先解析配置文件,并根据配置文件指定的信息,通过反射调用静态工厂类的静态工厂方法,并将该静态工厂方法的返回值作为Bean实例,在这个过程中,Spring不再负责创建Bean实例,Bean实例是由用户提供的静态工厂方法提供的。

实例化工厂方式创建 Bean

相比较静态工厂实现

1、工厂方法为非静态方法

2、需要配置工厂bean,并在业务bean中配置factory-bean,factory-method属性

实例化工厂定义

/**

  • 实例化工厂
  • @author Best Liu

*
*/
public class InstanceFactory {
public OrderService createOrderService() {
return new OrderService();
}
}

实体类定义

public class OrderService {
public void getOrderInfo() {
System.out.println("亲,已经下单完成,但是想发货没门");
}
}

Bean配置

<!--
实例化工厂
1、定义实例化工厂bean
2、引用工厂bean指定工厂创建方法(方法为非静态)
-->
<bean id="instanceFactory" class="com.xxx.demo.InstanceFactory"></bean>
<bean id="orderService" factory-bean="instanceFactory" factory-method="createOrderService"></bean>

扩展

Spring 三种实例化 bean 的方式比较

方式一:通过bean的缺省构造函数创建,当各个bean的业务逻辑相互比较独立的时候或者和外界关联较少的时候可以使用。

方式二:利用静态factory方法创建,可以统一管理各个bean的创建,如各个bean在创建之前需要相同的初始化处理,则可用这个factory方法先进行统一的处理等等。

方式三:利用实例化factory方法创建,即将factory方法也作为了业务bean来控制,

1、可用于集成其他框架的bean创建管理方法

2、能够使bean和factory的角色互换

开发中项目一般使用一种方式实例化bean,项目开发基本采用第一种方式,交给spring托管,使用时直接拿来使用即可,另外两种了解即可。

查看原文

赞 0 收藏 0 评论 0

爱编程的小叮当 发布了文章 · 1月14日

Mybatis框架如何使用分页插件呢?

分页插件使用的方式

  • 修改 pom 文件,添加分页 jar 包依赖
  • 修改 mybatis.xml 文件
  • UserDao 接口,UserMapper.xml 添加对应方法与实现 sql
  • 对应 UserService 接口添加分页查询方法
  • 测试分页效果

案例实操

1.修改 pom 文件,添加分页 jar 包依赖

<dependency>

<groupId>com.github.pagehelper</groupId>

<artifactId>pagehelper</artifactId>

<version>4.1.0</version>

</dependency>

2.修改 mybatis.xml 文件

<plugins>

<!-- com.github.pagehelper 为 PageHelper 类所在包名 -->

<plugin interceptor="com.github.pagehelper.PageHelper">

<property name="dialect" value="mysql" />

<!-- 该参数默认为 false -->

<!-- 设置为 true 时,会将 RowBounds 第一个参数 offset 当成 pageNum 页码使用

-->

<!-- 和 startPage 中的 pageNum 效果一样 -->

<property name="offsetAsPageNum" value="true" />

<!-- 该参数默认为 false -->

<!-- 设置为 true 时,使用 RowBounds 分页会进行 count 查询 -->

<property name="rowBoundsWithCount" value="true" />

<!-- 设置为 true 时,如果 pageSize=0 或者 RowBounds.limit = 0 就会查询出全

部的结果 -->

<!-- (相当于没有执行分页查询,但是返回结果仍然是 Page 类型) -->

<property name="pageSizeZero" value="true" />

<!-- 3.3.0 版本可用 - 分页参数合理化,默认 false 禁用 -->

<!-- 启用合理化时,如果 pageNum<1 会查询第一页,如果 pageNum>pages 会查询

最后一页 -->

<!-- 禁用合理化时,如果 pageNum<1 或 pageNum>pages 会返回空数据 -->

<property name="reasonable" value="true" />

<!-- 3.5.0 版本可用 - 为了支持 startPage(Object params)方法 -->

<!-- 增加了一个params参数来配置参数映射,用于从 Map 或 ServletRequest

中取值 -->

<!-- 可以配置 pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射

的用默认值 -->

<property name="params"

value="pageNum=start;pageSize=limit;pageSizeZero=zero;reasonable=heli;count=cou

ntsql" />

</plugin>

</plugins>

3.UserDao 接口,UserMapper.xml 添加对应方法与实现 sql

UserDao 接口:

public interface UserDao {

public User queryUserById(int id);

public List<User> queryUsers();

}

UserMapper.xml

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

<!DOCTYPE mapper

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.mage.dao.UserDao">

<select id="queryUserById" parameterType="int" resultType="user">

select id,userName,userPwd from user where id=#{id}

</select>

<select id="queryUsers" resultType="user">

select id,userName,userPwd from user

</select>

</mapper>

4.对应 UserService 接口添加分页查询方法

public interface UserService {

public User queryUserById();

/**

  • 分页方法定义

  • @param pageNum 当前页号

  • @param pageSize 设置每页显示数量

  • @return


*/

public PageInfo<User> queryUsers(int pageNum,int pageSize);

}

UserServiceImpl 实现方法:

@Service

public class UserServiceImpl implements UserService{

@Resource

private UserDao userDao;

public User queryUserById(){

return userDao.queryUserById(7);

}

@Override

public PageInfo<User> queryUsers(int pageNum, int pageSize) {

/**

  • PageHelper 类设置分页页号与每页大小


*/

PageHelper.startPage(pageNum, pageSize);

List<User> list=userDao.queryUsers();

PageInfo<User> pageInfo=new PageInfo<User>(list);

return pageInfo;

}

}

5.测试分页效果

数据库原始记录

测试

第一次 PageNum =1 pageSize=1

@Test

public void testQueryUsers() {

PageInfo<User> pageInfo= userService.queryUsers(1, 1);

for(User user:pageInfo.getList()){

System.out.println("user:"+user);

}

}

结果:

第二次 pageNum=2 pageSize=1

@Test

public void testQueryUsers() {

PageInfo<User> pageInfo= userService.queryUsers(2, 1);

for(User user:pageInfo.getList()){

System.out.println("user:"+user);

}

}

结果

备注:分页插件 如果传入的页码 操作记录总页数 此时我们得到的是最后一页的记录

第三次测试 PageNum=3 pageSize=1

@Test

public void testQueryUsers() {

PageInfo<User> pageInfo= userService.queryUsers(3, 1);

for(User user:pageInfo.getList()){

System.out.println("user:"+user);

}

}

结果:

扩展

分页插件压缩版

解压即可使用,和之前配置一样去配置好 config.xml,再运行 run.bat 即可

查看原文

赞 0 收藏 0 评论 0

爱编程的小叮当 发布了文章 · 1月12日

Web发展中通信的方式有哪些呢?

​ ### 1 简单通信

回顾 Socket 编程给我们最大的感受,是可以在多台电脑之间进行数据的传输,这就是网络编程的开端和基础,通过客户端请求服务器端通信,直观了解 Web 编程。

Server

/**

  • 服务端,接收客户端请求并给出简单的响应
  • @author Cushier

*
*/
public class Server {

public static void main(String[] args) throws IOException{
// 创建服务器,指定端口ServerSocket(int port)
ServerSocket socket = new ServerSocket(8888);
// 接收客户端连接
Socket client = socket.accept();
System.out.println("**");
// 获取数据的输入流
InputStream is = client.getInputStream();
// 使用缓冲字符输入流
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String msg = "";
while ((msg = br.readLine()) != null) {
System.out.println(msg);
}
br.close();
}

}

Client

/**

  • 客户端:向服务器发送请求,并发送简单的消息
  • @author Cushier

*
*/
public class Client {

public static void main(String[] args) throws UnknownHostException, IOException {
// 创建客户端 必须指定服务器+端口
Socket client = new Socket("localhost", 8888);
// 发送消息 请求资源
// 获取输出流
OutputStream os = client.getOutputStream();
// 使用缓冲字符输出流
BufferedWriter br = new BufferedWriter(new OutputStreamWriter(os));
// 写出消息,发送内容
String msg = "Hello, I am Client, I need some resources";
br.write(msg);
br.close();
}

}

服务端控制台:

从上面的例子总结通信条件如下:

  1. 需要有服务器端(server):等待被请求,需要暴露 ip 和 port
  2. 需要有客户端(client):主动发起请求,知晓服务端的 ip 和 port
  3. 通信规则(协议):TCP/IP 协议

    ip 用于定位计算机;端口号(定位程序),用于标识进程的逻辑地址,不同进程的标志;有效端口:0~65535,其中 0~1024 由系统使用或者保留端口,开发中建议使用 1024 以上的端口。

2 不同请求

Client

/**

  • 客户端:向服务器发送请求,发送不同的请求
  • @author Cushier

*
*/
public class Client {

public static void main(String[] args) throws IOException {
// 通过系统默认类型的 SocketImpl 创建未连接套接字
Socket socket = new Socket();
// 此类实现 IP 套接字地址(IP 地址 + 端口号)。它还可以是一个对(主机名 + 端口号),在此情况下,将尝试解析主机名
SocketAddress address = new InetSocketAddress("localhost", 8898);
// 将此套接字连接到服务器,并指定一个超时值。或者不指定超时时间
socket.connect(address, 1000);
OutputStream os = socket.getOutputStream();
os.write("time".getBytes());
os.flush();
socket.close();
}

}

Server

/**

  • 服务端
  • public class ServerSocketextends Object:此类实现服务器套接字。
  • 服务器套接字等待请求通过网络传入。
  • 它基于该请求执行某些操作,然后可能向请求者返回结果。
  • @author Cushier

*
*/
public class Server {

public static void main(String[] args) throws IOException {
// 创建绑定到特定端口的服务器套接字。
ServerSocket server = new ServerSocket(8898);

// Socket accept() 侦听并接受到此套接字的连接。
Socket client = server.accept();
System.out.println("接收到连接");

InputStream is = client.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
byte[] req = new byte[1024];
// 接收客户端请求
int len = bis.read(req);
String reqStr = new String(req, 0, len);
System.out.println(reqStr);
if (reqStr.equals("money")) {
System.out.println("here's the money");
} else if (reqStr.equals("time")) {
System.out.println("you have so much time");
}
client.close();
server.close();
}

}

服务端控制台:

3 复杂请求

Client

/**

  • 客户端
  • @author Cushier

*
*/
public class Client {

public static void main(String[] args) throws IOException {
// 通过系统默认类型的 SocketImpl 创建未连接套接字
Socket socket = new Socket();
// 此类实现 IP 套接字地址(IP 地址 + 端口号)。它还可以是一个对(主机名 + 端口号),在此情况下,将尝试解析主机名
SocketAddress address = new InetSocketAddress("localhost", 8898);
// 将此套接字连接到服务器,并指定一个超时值。或者不指定超时时间
socket.connect(address, 1000);

OutputStream os = socket.getOutputStream();
os.write("money".getBytes());
os.flush();
// 接收响应,显示结果
InputStream is = socket.getInputStream();
byte[] result = new byte[1024];
int len = is.read(result);
String resultStr = new String(result, 0, len);
System.out.println(resultStr);
socket.close();
}

}

Server

/**

  • 服务端
  • @author Cushier

*
*/
public class Server2 {

public static void main(String[] args) throws IOException {
// 创建绑定到特定端口的服务器套接字。
ServerSocket server = new ServerSocket(8898);

// Socket accept() 侦听并接受到此套接字的连接。
Socket client = server.accept();
System.out.println("接收到连接");
InputStream is = client.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
byte[] req = new byte[1024];
// 接收客户端请求
int len = bis.read(req);
String reqStr = new String(req, 0, len);
System.out.println(reqStr);
// 将接收到的请求封装成对象,传送给请求的类
MyRequest request = new MyRequest();
MyResponse response = new MyResponse();

OutputStream os = client.getOutputStream();
if (reqStr.equals("money")) {
// 根据请求的信息,构造处理的类
MyServlet s1 = new ServletMoney();
s1.service(request, response);
// 通过client的响应,将结果响应回客户端
os.write("here's the money".getBytes());
os.flush();
} else if (reqStr.equals("time")) {
// 根据请求的信息,构造处理的类
MyServlet s2 = new ServletTime();
s2.service(request, response);
// 通过client的响应,将结果响应回客户端
os.write("you have somuch time".getBytes());
os.flush();
}
client.close();
server.close();
}

}

/*

  • 我是一个有要求的人,你请求的这个资源必须是满足我要求格式的类,作用:防止混乱,方便调用 这是我的标准

*/
interface MyServlet {
void service(MyRequest req, MyResponse resp);
}

class ServletMoney implements MyServlet {
@Override
public void service(MyRequest req, MyResponse resp) {
// 做出力所能及的处理
}
}

class ServletTime implements MyServlet {
@Override
public void service(MyRequest req, MyResponse resp) {
// 做出力所能及的处理
}
}

/*

  • 请求信息都按规律封装在该对象

*/
class MyRequest {
}

class MyResponse {
}

服务端控制台: 客户端控制台:

随着客户需求越来越复杂,需要的功能越来越多,我们的服务器端需要处理的请求越来越多,需要区分不同的请求,还需要按照不同请求进行请求数据的提取以及资源的分配和运算还有逻辑的处理,最后还需要响应给客户端,这就使得服务器端代码越来越复杂,实现越来越困难

根据以往的经验,双方进行通信只需要遵循一定的规则就可以很明确地知道各部分数据的含义,于是出现了网络更上层的应用协议(后面讲的 HTTP 协议),规定服务器端和客户端通信的规则。

客户端请求服务器端和服务器端响应客户端,都按照固定的规则,那么接收请求和响应数据这部分操作就可以固定下来,交给特定的一段代码来执行,从而减少服务器端的代码量,于是出现了接下来说的服务器

扩展

服务器的出现

当客户端请求的资源越来越丰富,需求越来越复杂,程序的核心就应该放在解决业务和计算响应数据上,于是出现了服务器统一接收客户端数据进行处理并分发到不同的资源,由各个资源进行处理,最后结果交由服务器响应。

从上面的描述可以发现,现在所说的服务器只是负责接收请求,对请求进行分发,以及最后将获取的数据进行相应的固定框架,至于数据怎么计算得出还得根据具体的业务需求编写(填充)代码。在没有业务需求的情况下就能将服务器准备出来,现在市面上的服务器有很多,比较常用的有:Tomcat、JBOOS、IBM 的 WebSphere、BEA的 WebLogic 以及 Apache 等。

查看原文

赞 0 收藏 0 评论 0

爱编程的小叮当 发布了文章 · 1月8日

BootStrap

​ Bootstrap 是一套现成的 CSS 样式集合(做得还是很友好的)。是两个推特的员工干出来的。

​ Bootstrap 是最受欢迎的 HTML、CSS 和 JS 框架,用于开发响应式布局、移动设备优先的 WEB 项目。

​ 2011年,twitter 的"一小撮"工程师为了提高他们内部的分析和管理能力,用业余时间为他们的产品构建了一套易用、优雅、灵活、可扩展的前端工具集 -- BootStrap。Bootstrap 由 MARK OTTO 和 Jacob Thornton 所设计和建立,在 github上开源之后,迅速成为该站上最多人 watch&fork 的项目。大量工程师踊跃为该项目贡献代码,社区惊人地活跃,代码版本进化非常快速,官方文档质量极其高(可以说是优雅),同时涌现了许多基于Bootstrap 建设的网站:界面清新、简洁;要素排版利落大方。

​ Bootstrap特别适合那种没有设计师的团队(甚至说没有前端的团队),可以快速的出一个网页。

BootStrap 特点

  1. 简洁、直观、强悍的前端开发框架,html、css、javascript 工具集,让 web 开发更速、简单。
  2. 基于html5、css3的bootstrap,具有大量的诱人特性:友好的学习曲线,卓越的兼容性,响应式设计,12列格网,样式向导文档。
  3. 自定义 JQuery 插件,完整的类库,bootstrap3 基于Less,bootstrap4 基于 Sass 的 CSS 预处理技术
  4. Bootstrap 响应式布局设计,让一个网站可以兼容不同分辨率的设备。Bootstrap 响应式布局设计,给用户提供更好的视觉使用体验。
  5. 丰富的组件

下载与使用

  1. 下载:http://v3.bootcss.com/getting...
  2. 下载完成后

    拷贝 dist/css 中的 bootstrap.min.css 到项目 css 中

    拷贝 dist/js 中的 bootstrap.min.js 到项目的 js 中

  3. 下载 jquery.js

    http://jquery.com/

  4. 在 html 中模板为:
<!DOCTYPE html>
<html lang="en">
  <head>
     <meta charset="utf-8">
     <!--使用X-UA-Compatible来设置IE浏览器兼容模式 最新的渲染模式-->    
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <!--
        viewport表示用户是否可以缩放页面;
        width指定视区的逻辑宽度;
        device-width指示视区宽度应为设备的屏幕宽度;
        initial-scale指令用于设置Web页面的初始缩放比例
        initial-scale=1则将显示未经缩放的Web文档
     -->
     <meta name="viewport" content="width=device-width, initial-scale=1">
     <title>Bootstrap的HTML标准模板</title>   
     <!-- 载入Bootstrap 的css -->
     <link href="css/bootstrap.min.css" rel="stylesheet">
  </head>
  <body>
      <h1>Hello, world!</h1>     
      
    <!-- 如果要使用Bootstrap的js插件,必须先调入jQuery -->
      <script data-original="js/jquery-3.4.1.js"></script>
      <!-- 包括所有bootstrap的js插件或者可以根据需要使用的js插件调用 -->
      <script data-original="js/bootstrap.min.js"></script> 
  </body>    
</html>

​ 注意:

​ <font color="red">目前暂时不使用 jquery 的插件 可以不用引入 js 文件,这里是为了保证模板的完整性。</font>

说明:

  • viewport <meta>标记用于指定用户是否可以缩放Web页面
  • width 和 height 指令分别指定视区的逻辑宽度和高度。他们的值要么是以像素为单位的数字,要么是一个特殊的标记符号。
  • width 指令使用 device-width 标记可以指示视区宽度应为设备的屏幕宽度。
  • height 指令使用 device-height 标记指示视区高度为设备的屏幕高度。
  • initial-scale 指令用于设置Web页面的初始缩放比例。默认的初始缩放比例值因智能手机浏览器的不同而有所差异。通常情况下设备会在浏览器中呈现出整个Web页面,设为1.0则将显示未经缩放的Web文档。
  1. 参考API

    http://v3.bootcss.com/css/

布局容器和栅格网格系统

布局容器

​ 1、.container 类用于固定宽度并支持响应式布局的容器。

<div class="container">
  ...
</div>

​ 2、.container-fluid类用于100% 宽度,占据全部视口(viewport)的容器。

<div class="container-fluid">
  ...
</div>

栅格网格系统

​ Bootstrap 提供了一套响应式、移动设备优先的流式栅格系统,随着屏幕或视口(viewport)尺寸的增加,系统会自动分为最多12列。栅格系统用于通过一系列的行(row)与列(column)的组合来创建页面布局,你的内容就可以放入这些创建好的布局中。

​ 网格系统的实现原理非常简单,仅仅是通过定义容器大小,平分12份(也有平分成24份或32份,但12份是最常见的),再调整内外边距,最后结合媒体查询,就制作出了强大的响应式网格系统。Bootstrap框架中的网格系统就是将容器平分成12份。

​ 注意: 网格系统必须使用到css

​ container、row 、xs (xsmall phones),sm (small tablets),md (middle desktops),lg (larger desktops) 即: 超小屏(自动),小屏(750px),中屏(970px)和大屏(1170px)

​ 数据行(.row)必须包含在容器(.container)中,以便为其赋予合适的对齐方式和内距(padding)。

​ 在行(.row)中可以添加列(.column), 只有列(column)才可以作为行容器(.row)的直接子元素,但列数之和不能超过平分的总列数,比如12。如果大于12,则自动换到下一行。

​ 具体内容应当放置在列容器(column)之内

<div class="container">
    <div class="row">
      <div class="col-md-4">4列</div>
      <div class="col-md-8">8列</div>
    </div>
</div>

列组合

​ 列组合简单理解就是更改数字来合并列(原则:列总和数不能超12,大于12,则自动换到下一行。),有点类似于表格的colspan属性。

<div class="container">
    <div class="row">
        <div class="col-md-4">4列</div>
        <div class="col-md-8">8列</div>
    </div>
    <div class="row">
          <div class="col-md-2">2列</div>
          <div class="col-md-10">10列</div>
    </div>
</div>

列偏移

​ 如果我们不希望相邻的两个列紧靠在一起,但又不想使用margin或者其他的技术手段来。这个时候就可以使用列偏移(offset)功能来实现。使用列偏移也非常简单,只需要在列元素上添加类名"col-md-offset-*"(其中星号代表要偏移的列组合数),那么具有这个类名的列就会向右偏移。例如,你在列元素上添加"col-md-offset-8",表示该列向右移动8个列的宽度(要保证列与偏移列的总数不超过12,不然会致列断行|换行显示)。

<div class="container">
    <div class="row">
          <div class="col-md-1">1列</div>
          <div class="col-md-1">2列</div>
          <div class="col-md-1 col-md-offset-8">11列</div>
          <div class="col-md-1">12列</div>
    </div>
</div>

列排序

​ 列排序其实就是改变列的方向,就是改变左右浮动,并且设置浮动的距离。在Bootstrap框架的网格系统中是通过添加类名 col-md-push- 和 col-md-pull- (其中星号代表移动的列组合数)。往前pull,往后push。

<div class="container">
    <div class="row">
        <div class="col-md-1 col-md-push-10">1列</div>
        <div class="col-md-1 col-md-pull-1">2列</div>    
    </div>
</div>

列嵌套

​ Bootstrap框架的网格系统还支持列的嵌套。你可以在一个列中添加一个或者多个行(row)容器,然后在这个行容器中插入列.

<div class="container">
    <div class="row">
        <div class="col-md-2">
            我的里面嵌套了一个网格
            <div class="row">
                <div class="col-md-9">9</div>
                <div class="col-md-3">3</div>
            </div>
        </div>
        <div class="col-md-10">我的里面嵌套了一个网格
            <div class="row">
                <div class="col-md-10">10</div>
                <div class="col-md-2">2</div>
            </div>
        </div>                
    </div>
</div>

常用样式

排版

标题

​ Bootstrap和普通的HTML页面一样,定义标题都是使用标签<h1>到<h6>,只不过Bootstrap覆盖了其默认的样式,使用其在所有浏览器下显示的效果一样。为了让非标题元素和标题使用相同的样式,还特意定义了.h1~.h6六个类名。同时后面可以紧跟着一行小的副标题或使用.small

<h1>h1. Bootstrap heading<small>副标题</small></h1>
<div class="h1">Bootstrap标题1<span class="small">副标题</span></div>

段落

​ 段落是排版中另一个重要元素之一。通过.lead 来突出强调内容(其作用就是增大文本字号,加粗文本,而且对行高和margin也做相应的处理。可以使用以下标签给文本做突出样式处理:

​ :小号字

:加粗

:斜体

<p class="lead"><small>以后的</small><b>你</b>会<i>感谢</i>现在<em>努力</em>的<strong>你</strong></p>

强调

​ 定义了一套类名,这里称其为强调类名,这些强调类都是通过颜色来表示强调,具本说明如下:

​ .text-muted:提示,使用浅灰色(#999)

       .text-primary:主要,使用蓝色(#428bca)

        .text-success:成功,使用浅绿色(#3c763d)

        .text-info:通知信息,使用浅蓝色(#31708f)

        .text-warning:警告,使用黄色(#8a6d3b)

        .text-danger:危险,使用褐色(#a94442)
<div class="text-muted">提示效果</div>
<div class="text-primary">主要效果</div>
<div class="text-success">成功效果</div>
<div class="text-info">信息效果</div>
<div class="text-warning">警告效果</div>
<div class="text-danger">危险效果</div>

对齐效果

​ 在CSS中常常使用text-align来实现文本的对齐风格的设置。

​ 其中主要有四种风格:

​ 左对齐,取值left ;

​ 居中对齐,取值center;

​ 右对齐,取值right ;

​ 两端对齐,取值justify。

​ 为了简化操作,方便使用,Bootstrap通过定义四个类名来控制文本的对齐风格:.text-left:左对齐 .text-center:居中对齐 .text-right:右对齐 .text-justify:两端对齐。

<p class="text-left">我居左</p>
<p class="text-center">我居中</p>
<p class="text-right">我居右</p>
<p class="text-justify">网格系统的实现原理非常简单,仅仅是通过定义容器大小,平分12份(也有平分成24份或32份,但12份是最常见的),再调整内外边距,最后结合媒体查询,就制作出了强大的响应式网格系统。Bootstrap框架中的网格系统就是将容器平分成12份</p>

列表

​ 在HTML文档中,列表结构主要有三种:

​ 无序列表(<ul><li>…</li></ul>)

​ 有序列表(<ol><li>…</li></ol>)

​ 定义列表(<dl><dt>…</dt><dd>…</dd></dl>)

去点列表

​ class="list-unstyled"

<ul class="list-unstyled">
    <li>无序项目列表一</li>
    <li>无序项目列表二</li>
</ul>
内联列表

​ class="list-inline",把垂直列表换成水平列表,而且去掉项目符号(编号),保持水平显示。也可以说内联列表就是为制作水平导航而生。

<ul class="list-inline">
    <li>首页</li>
    <li>java学院</li>
    <li>在线课堂</li>
</ul>
定义列表

​ 在原有的基础加入了一些样式,使用样式 class="dl-horizontal" 制作水平定义列表 : 当标题宽度超过160px时,将会显示三个省略号。

<dl>
    <dt>HTML</dt>
    <dd>超文本标记语言</dd>
    <dt>CSS</dt>
    <dd>层叠样式表是一种样式表语言</dd>
</dl>
<dl class="dl-horizontal">
    <dt>HTML 超文本标记语言</dt>
    <dd>HTML称为超文本标记语言,是一种标识性的语言。</dd>           
    <dt>测试标题不能超过160px的宽度,否则2个点</dt>
    <dd>我在写一个水平定义列表的效果,我在写一个水平定义列表的效果。</dd>
</dl>

代码

​ 一般在个人博客上使用的较为频繁,用于显示代码的风格。在Bootstrap主要提供了三种代码风格:

​ (1)使用来显示单行内联代码

​ (2)使用<pre></pre>来显示多行块代码

​ 样式:pre-scrollable (height,max-height高度固定,为340px,超过存在滚动条)

​ (3)使用来显示用户输入代码,如快捷键

单行内联代码
<code>this is a simple code</code>
快捷键
<p>使用<kbd>ctrl+s</kbd>保存</p>
多行块代码
<!-- 代码会保留原本的格式,包括空格和换行 -->
<pre>
public class HelloWorld {
    public static void main(String[] args){
        System.out.println("helloworld...");
    }
}
</pre>
<!-- 
    显示html标签的代码需要适应字符实体  
    小于号(<)要使用硬编码“&lt;”来替代,大于号(>)使用“&gt;”来替代 
-->
<pre>
    &lt;ul&gt;
        &lt;li&gt;测试实体符&lt;/li&gt;
    &lt;/ul&gt;
</pre>
<!-- 当高度超过,会存在滚动条 -->
<pre class="pre-scrollable">
    <ol>
        <li>...........</li>
        <li>...........</li>
        <li>...........</li>
        <li>...........</li>
        <li>...........</li>
        <li>...........</li>
        <li>...........</li>
        <li>...........</li>
        <li>...........</li>
        <li>...........</li>
        <li>...........</li>
        <li>...........</li>
    </ol>
</pre>

表格

表格样式

​ Bootstrap为表格提供了1种基础样式和4种附加样式以及1个支持响应式的表格。在使用Bootstrap的表格过程中,只需要添加对应的类名就可以得到不同的表格风格:

基础样式

​ 1).table:基础表格

附加样式

​ 1) .table-striped:斑马线表格

​ 2) .table-bordered:带边框的表格

​ 3) .table-hover:鼠标悬停高亮的表格

​ 4). table-condensed:紧凑型表格,单元格没内距或者内距较其他表格的内距小

tr、th、td样式

​ 提供了五种不同的类名,每种类名控制了行的不同背景颜色

描述实例
.active将悬停的颜色应用在行或者单元格上<font color="#f5f5f5">#f5f5f5</font>
.success表示成功的操作<font color="#dff0d8">#dff0d8</font>
.info表示信息变化的操作<font color="#d9edf7">#d9edf7</font>
.warning表示一个警告的操作<font color="#fcf8e3">#fcf8e3</font>
.danger表示一个危险的操作<font color="#f2dede">#f2dede</font>
<table class="table table-bordered table-hover">
    <tr class="active">
        <th>JavaSE</th>
        <th>数据库</th>
        <th>JavaScript</th>
    </tr>
    <tr class="danger">
        <td>面向对象</td>
        <td>oracle</td>
        <td>json</td>
    </tr>
    <tr class="success">
        <td>数组</td>
        <td>mysql</td>
        <td>ajax</td>
    </tr>
</table>

表单

​ 表单主要功能是用来与用户做交流的一个网页控件,良好的表单设计能够让网页与用户更好的沟通。表单中常见的元素主要包括:文本输入框、下拉选择框、单选按钮、复选按钮、文本域和按钮等。

表单控件

​ .form-control .input-lg(较大) .input-sm(较小)

输入框 text

​ .form-control

<div class="col-sm-3">
    <input type="text" name="" id="" class="form-control" />
    <input type="text" name="" id="" class="form-control input-lg" />
    <input type="text" name="" id="" class="form-control input-sm" />
</div>
下拉选择框 select

​ 多行选择设置:multiple="multiple"

<div class="col-sm-3">
    <select class="form-control">
        <option>北京</option>
        <option>上海</option>
        <option>深圳</option>
    </select>
    <select class="form-control" multiple="multiple">
        <option>北京</option>
        <option>上海</option>
        <option>深圳</option>
    </select>
</div>
文本域 textarea
<div class="col-sm-3">
    <textarea class="form-control" rows="3"></textarea>
</div>
复选框 checkbox

​ 垂直显示: .checkbox

​ 水平显示: .checkbox-inline

<!-- 垂直显示 -->
<div>
    <div class="checkbox">
        <label><input type="checkbox" >游戏</label>
    </div>
    <div class="checkbox">
        <label><input type="checkbox" >学习</label>
    </div>
</div>
<!-- 水平显示 -->
<div>
    <label class="checkbox-inline">
        <input type="checkbox" >游戏
    </label>
    <label class="checkbox-inline">
        <input type="checkbox" >学习
    </label>
</div>
单选框 radio

​ 垂直显示: .radio

​ 水平显示: .radio-inline

<!-- 垂直显示 -->
<div>
    <div class="radio">
        <label><input type="radio" >男</label>
    </div>
    <div class="radio">
        <label><input type="radio" >女</label>
    </div>
</div>
<!-- 水平显示 -->
<div>
    <label class="radio-inline">
        <input type="radio" >男
    </label>
    <label class="radio-inline">
        <input type="radio" >女
    </label>
</div>
按钮

1)使用 button 实现

​ 基础样式: btn

<button class="btn">按钮</button>

​ 附加样式:btn-primary btn-info btn-success btn-warning btn-danger btn-link btn-default

<button class="btn btn-danger">按钮</button>
<button class="btn btn-primary">按钮</button>
<button class="btn btn-info">按钮</button>
<button class="btn btn-success">按钮</button>
<button class="btn btn-default">按钮</button>
<button class="btn btn-warning">按钮</button>
<button class="btn btn-link">按钮</button>

2)多标签支持:使用 a div 等制作按钮

<a href="##" class="btn btn-info">a标签按钮</a>
<span class="btn btn-success">span标签按钮</span>
<div class="btn btn-warning">div标签按钮</div>

3)按钮大小

​ 使用 .btn-lg、.btn-sm 或 .btn-xs 就可以获得不同尺寸的按钮

<button class="btn btn-primary btn-xs">超小按钮.btn-xs</button>
<button class="btn btn-primary btn-sm">小型按钮.btn-sm</button>
<button class="btn btn-primary">正常按钮</button>
<button class="btn btn-primary btn-lg">大型按钮.btn-lg</button> 

4)按钮禁用

​ 方法1:在标签中添加disabled属性

<button class="btn btn-danger" disabled="disabled">禁用按钮</button>

​ 方法2:在元素标签中添加类名"disabled"

<button class="btn btn-danger disabled">禁用按钮</button>

​ 在class属性中添加disabled只是样式上禁用了,并不是真正的禁用了此按钮!

表单布局

​ 基本的表单结构是 Bootstrap 自带的,个别的表单控件自动接收一些全局样式。下面列出了创建基本表单的步骤:

  • 向父 <form> 元素添加 role="form"
  • 把标签和控件放在一个带有 class .form-group 的 <div> 中。这是获取最佳间距所必需的。
  • 向所有的文本元素 <input>、<textarea> 和 <select> 添加 class ="form-control" 。
水平表单

​ 同一行显示form-horizontal

​ 配合Bootstrap框架的网格系统

<form class="form-horizontal" role="form">
    <div class="form-group">
        <label for="email" class="control-label col-sm-2">邮箱</label>
        <div class="col-sm-10">
            <input type="email" class="form-control" placeholder="请输入邮箱"/>
        </div>
    </div>
    <div class="form-group">
        <label for="pwd" class="control-label col-sm-2">密码</label>
        <div class="col-sm-10">
            <input type="pwd" class="form-control" placeholder="请输入密码" />
        </div>
    </div>
    <div class="form-group">
        <div class="col-sm-offset-2">
            <div class=" checkbox">
                <label>
                    <input type="checkbox" />记住密码
                </label>
            </div>
        </div>
    </div>
    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
            <button class="btn btn-default">提交</button>
        </div>
    </div>
</form>
内联表单

​ 将表单的控件都在一行内显示form-inline

​ 注意label不会显示,存在的意义:如果没有为输入控件设置label标签,屏幕阅读器将无法正确识别。

<form class="form-inline">
    <div class="form-group">
        <label for="email" >邮箱</label>
        <input type="email" class="form-control" placeholder="请输入邮箱"/>
    </div>
    <div class="form-group">
        <label for="pwd" >密码</label>
            <input type="pwd" class="form-control" placeholder="请输入密码" />
    </div>
    <div class="form-group checkbox">
        <label><input type="checkbox" />记住密码</label>
    </div>
    <div class="form-group">
        <button class="btn btn-default">提交</button>
    </div>
</form>

缩略图

​ 缩略图在电商类的网站很常见,最常用的地方就是产品列表页面。缩略图的实现是配合网格系统一起使用。同时还可以让缩略图配合标题、描述内容,按钮等。

<div class="container">
    <div class="row">
        <div class="col-md-3">
               <div class="thumbnail">
                   ![](img/IMG_0131.JPG)
                   <h3>高圆圆</h3>
                   <p>出生于北京市,中国内地影视女演员、模特。</p>
                   <button class="btn btn-default">
                    <span class="glyphicon glyphicon-heart"></span>喜欢</button>
                   <button class="btn btn-info">
                    <span class="glyphicon glyphicon-pencil"></span>评论
                </button>
               </div>
        </div>
    </div>
</div>

面板

​ 默认的 .panel组件所做的只是设置基本的边框(border)和内补(padding)来包含内容。

​ .panel-default:默认样式

​ .panel-heading:面板头

​ .panel-body:面板主体内容

<div class="panel panel-success">
    <div class="panel-heading">
        ......
    </div>
    <div class="panel-body">
        ......
    </div>
</div>

BootStrap 插件

导航

​ 使用下拉与按钮组合可以制作导航

​ 要点:

1、基本样式: .nav 与 “nav-tabs”、“nav-pills”组合制作导航
2、分类: 
    1)、标签型 (nav-tabs)导航
    2)、胶囊形(nav-pills)导航
    3)、堆栈(nav-stacked)导航
    4)、自适应(nav-justified)导航
    5)、面包屑式(breadcrumb)导航 ,单独使用样式,不与nav一起使用,直接加入到ol、ul中即可,一般用于导航,主要是起的作用是告诉用户现在所处页面的位置(当前位置)
3、状态:
    1)、选中状态 active 样式
    2)、禁用状态: disable
4、二级菜单

标签式导航

<p>标签式的导航菜单</p>
<ul class="nav nav-tabs">
  <li class="active"><a href="#">Home</a></li>
  <li><a href="#">SVN</a></li>
  <li><a href="#">iOS</a></li>
  <li><a href="#">VB.Net</a></li>
  <li><a href="#">Java</a></li>
  <li><a href="#">PHP</a></li>
</ul>

胶囊式导航

<p>基本的胶囊式导航菜单</p>
<ul class="nav nav-pills">
    <li class="active"><a href="#">Home</a></li>
    <li><a href="#">SVN</a></li>
    <li><a href="#">iOS</a></li>
    <li><a href="#">VB.Net</a></li>
    <li><a href="#">Java</a></li>
    <li><a href="#">PHP</a></li>
</ul>

分页导航

​ 分页随处可见,分为页码导航和翻页导航

​ 页码导航:ul标签上加pagination [pagination-lg | pagination-sm]

​ 翻页导航:ul标签上加pager

分页

<ul class="pagination">
    <li><a href="#">&laquo;</a></li>
    <li><a href="#">1</a></li>
    <li><a href="#">2</a></li>
    <li><a href="#">3</a></li>
    <li><a href="#">4</a></li>
    <li><a href="#">5</a></li>
    <li><a href="#">&raquo;</a></li>
</ul>

翻页

<ul class="pager">
    <li><a href="#">Previous</a></li>
    <li><a href="#">Next</a></li>
</ul>

下拉菜单

​ 在使用Bootstrap框架的下拉菜单时,必须使用两个js

<!-- 如果要使用Bootstrap的js插件,必须先调入jQuery -->
<script data-original="js/jquery-3.4.1.js"></script>
<!-- 包括所有bootstrap的js插件或者可以根据需要使用的js插件调用 -->
<script data-original="js/bootstrap.min.js"></script>

​ 要点:

1、使用一个类名为dropdown 或btn-group的div 包裹整个下拉框: 
   <div class="dropdown"></div>
2、默认向下dropdown,向上弹起加入 . dropup 即可
3、使用button作为父菜单,使用类名: dropdown-toggle 和自定义data-toggle属性
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"></button>
4、在button中 使用font 制作下拉箭头
    <span class="caret"></span>
5、下拉菜单项使用一个ul列表,并且定义一个类名为“dropdown-menu
6、分组分割线: <li>添加类名“divider”来实现添加下拉分隔线的功能
7、分组标题: li 添加类名 “dropdown-header” 来实现分组的功能
8、对齐方式:
    1)、dropdown-menu-left  左对齐 默认样式
    2)、dropdown-menu-right   右对齐
9、激活状态(.active)和禁用状态(.disabled)
<!--使用一个类名为dropdown,默认向下dropdown,向上弹起加入 . dropup 即可-->
<div class="dropdown ">
    <!--使用button作为父菜单,使用类名: dropdown-toggle 和自定义data-toggle属性-->
    <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
        喜欢频道 <span class="caret"></span><!--下拉箭头-->
    </button>
    <!--下拉菜单项使用一个ul列表,并且定义一个类名为“dropdown-menu-->
    <ul class="dropdown-menu">     <!--dropdown-menu-right右对齐-->
        <!--分组标题: li 添加类名 “dropdown-header” 来实现分组的功能-->
        <li class="dropdown-header">----科普----</li>
        <li>
            <a href="#">人与自然</a>
        </li>
        <!--分组分割线: <li>添加类名“divider”来实现添加下拉分隔线的功能-->
        <li class="divider"></li>
        <li class="dropdown-header">----搞笑----</li>
        <li>
            <a href="#">欢乐喜剧人</a>
        </li>
        <li>
            <a href="#">快乐大本营</a>
        </li>
        <li class="divider"></li>
        <li class="disabled">    <!--禁用状态-->
            <a href="#">生活大爆炸</a>
        </li>
    </ul>
</div>

模态框

​ 模态框(Modal)是覆盖在父窗体上的子窗体。通常,目的是显示来自一个单独的源的内容,可以在不离开父窗体的情况下有一些互动。子窗体可提供信息、交互等。

用法

  1. 通过 data 属性:在控制器元素(比如按钮或者链接)上设置属性 data-toggle="modal",同时设置 data-target="#identifier"href="#identifier" 来指定要切换的特定的模态框(带有 id="identifier")。
  2. 通过 JavaScript:使用这种技术,可以通过 JavaScript 来调用带有 id="identifier" 的模态框:
$('#identifier').modal(options);

实例

<h2>创建模态框(Modal)</h2>
<!-- 按钮触发模态框 -->
<button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
    开始演示模态框
</button>
<!-- 模态框(Modal) -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                <h4 class="modal-title" id="myModalLabel">模态框(Modal)标题</h4>
            </div>
            <div class="modal-body">在这里添加一些文本</div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
                <button type="button" class="btn btn-primary">提交更改</button>
            </div>
        </div><!-- /.modal-content -->
    </div><!-- /.modal -->
</div>

方法

方法描述实例
Toggle: .modal('toggle')手动切换模态框。$('#identifier').modal('toggle');
Show: .modal('show')手动打开模态框。$('#identifier').modal('show');
Hide: .modal('hide')手动隐藏模态框。`$('#identifier').modal('hide');Bootstrap 是一套现成的 CSS 样式集合(做得还是很友好的)。是两个推特的员工干出来的。

Bootstrap 是最受欢迎的 HTML、CSS 和 JS 框架,用于开发响应式布局、移动设备优先的 WEB 项目。

2011年,twitter 的"一小撮"工程师为了提高他们内部的分析和管理能力,用业余时间为他们的产品构建了一套易用、优雅、灵活、可扩展的前端工具集 -- BootStrap。Bootstrap 由 MARK OTTO 和 Jacob Thornton 所设计和建立,在 github上开源之后,迅速成为该站上最多人 watch&fork 的项目。大量工程师踊跃为该项目贡献代码,社区惊人地活跃,代码版本进化非常快速,官方文档质量极其高(可以说是优雅),同时涌现了许多基于Bootstrap 建设的网站:界面清新、简洁;要素排版利落大方。

Bootstrap特别适合那种没有设计师的团队(甚至说没有前端的团队),可以快速的出一个网页。

BootStrap 特点

  1. 简洁、直观、强悍的前端开发框架,html、css、javascript 工具集,让 web 开发更速、简单。
  2. 基于html5、css3的bootstrap,具有大量的诱人特性:友好的学习曲线,卓越的兼容性,响应式设计,12列格网,样式向导文档。
  3. 自定义 JQuery 插件,完整的类库,bootstrap3 基于Less,bootstrap4 基于 Sass 的 CSS 预处理技术
  4. Bootstrap 响应式布局设计,让一个网站可以兼容不同分辨率的设备。Bootstrap 响应式布局设计,给用户提供更好的视觉使用体验。
  5. 丰富的组件

下载与使用

  1. 下载:http://v3.bootcss.com/getting-started/
  2. 下载完成后

    拷贝 dist/css 中的 bootstrap.min.css 到项目 css 中

    拷贝 dist/js 中的 bootstrap.min.js 到项目的 js 中

  3. 下载 jquery.js

    http://jquery.com/

  4. 在 html 中模板为:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<!--使用X-UA-Compatible来设置IE浏览器兼容模式 最新的渲染模式-->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!--
viewport表示用户是否可以缩放页面;
width指定视区的逻辑宽度;
device-width指示视区宽度应为设备的屏幕宽度;
initial-scale指令用于设置Web页面的初始缩放比例
initial-scale=1则将显示未经缩放的Web文档
-->
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap的HTML标准模板</title>
<!-- 载入Bootstrap 的css -->
<link href="css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<h1>Hello, world!</h1>

<!-- 如果要使用Bootstrap的js插件,必须先调入jQuery -->
<script data-original="js/jquery-3.4.1.js"></script>
<!-- 包括所有bootstrap的js插件或者可以根据需要使用的js插件调用 -->
<script data-original="js/bootstrap.min.js"></script>
</body>
</html>

注意:

目前暂时不使用 jquery 的插件 可以不用引入 js 文件,这里是为了保证模板的完整性。

说明:

  • viewport <meta>标记用于指定用户是否可以缩放Web页面
  • width 和 height 指令分别指定视区的逻辑宽度和高度。他们的值要么是以像素为单位的数字,要么是一个特殊的标记符号。
  • width 指令使用 device-width 标记可以指示视区宽度应为设备的屏幕宽度。
  • height 指令使用 device-height 标记指示视区高度为设备的屏幕高度。
  • initial-scale 指令用于设置Web页面的初始缩放比例。默认的初始缩放比例值因智能手机浏览器的不同而有所差异。通常情况下设备会在浏览器中呈现出整个Web页面,设为1.0则将显示未经缩放的Web文档。
  1. 参考API

    http://v3.bootcss.com/css/

布局容器和栅格网格系统

布局容器

1、.container 类用于固定宽度并支持响应式布局的容器。

<div class="container">
...
</div>

2、.container-fluid类用于100% 宽度,占据全部视口(viewport)的容器。

<div class="container-fluid">
...
</div>

栅格网格系统

Bootstrap 提供了一套响应式、移动设备优先的流式栅格系统,随着屏幕或视口(viewport)尺寸的增加,系统会自动分为最多12列。栅格系统用于通过一系列的行(row)与列(column)的组合来创建页面布局,你的内容就可以放入这些创建好的布局中。

网格系统的实现原理非常简单,仅仅是通过定义容器大小,平分12份(也有平分成24份或32份,但12份是最常见的),再调整内外边距,最后结合媒体查询,就制作出了强大的响应式网格系统。Bootstrap框架中的网格系统就是将容器平分成12份。

注意: 网格系统必须使用到css

container、row 、xs (xsmall phones),sm (small tablets),md (middle desktops),lg (larger desktops) 即: 超小屏(自动),小屏(750px),中屏(970px)和大屏(1170px)

数据行(.row)必须包含在容器(.container)中,以便为其赋予合适的对齐方式和内距(padding)。

在行(.row)中可以添加列(.column), 只有列(column)才可以作为行容器(.row)的直接子元素,但列数之和不能超过平分的总列数,比如12。如果大于12,则自动换到下一行。

具体内容应当放置在列容器(column)之内

<div class="container">
<div class="row">
<div class="col-md-4">4列</div>
<div class="col-md-8">8列</div>
</div>
</div>

列组合

列组合简单理解就是更改数字来合并列(原则:列总和数不能超12,大于12,则自动换到下一行。),有点类似于表格的colspan属性。

<div class="container">
<div class="row">
<div class="col-md-4">4列</div>
<div class="col-md-8">8列</div>
</div>
<div class="row">
<div class="col-md-2">2列</div>
<div class="col-md-10">10列</div>
</div>
</div>

列偏移

如果我们不希望相邻的两个列紧靠在一起,但又不想使用margin或者其他的技术手段来。这个时候就可以使用列偏移(offset)功能来实现。使用列偏移也非常简单,只需要在列元素上添加类名"col-md-offset-*"(其中星号代表要偏移的列组合数),那么具有这个类名的列就会向右偏移。例如,你在列元素上添加"col-md-offset-8",表示该列向右移动8个列的宽度(要保证列与偏移列的总数不超过12,不然会致列断行|换行显示)。

<div class="container">
<div class="row">
<div class="col-md-1">1列</div>
<div class="col-md-1">2列</div>
<div class="col-md-1 col-md-offset-8">11列</div>
<div class="col-md-1">12列</div>
</div>
</div>

列排序

列排序其实就是改变列的方向,就是改变左右浮动,并且设置浮动的距离。在Bootstrap框架的网格系统中是通过添加类名 col-md-push- 和 col-md-pull- (其中星号代表移动的列组合数)。往前pull,往后push。

<div class="container">
<div class="row">
<div class="col-md-1 col-md-push-10">1列</div>
<div class="col-md-1 col-md-pull-1">2列</div>
</div>
</div>

列嵌套

Bootstrap框架的网格系统还支持列的嵌套。你可以在一个列中添加一个或者多个行(row)容器,然后在这个行容器中插入列.

<div class="container">
<div class="row">
<div class="col-md-2">
我的里面嵌套了一个网格
<div class="row">
<div class="col-md-9">9</div>
<div class="col-md-3">3</div>
</div>
</div>
<div class="col-md-10">我的里面嵌套了一个网格
<div class="row">
<div class="col-md-10">10</div>
<div class="col-md-2">2</div>
</div>
</div>
</div>
</div>

常用样式

排版

标题

Bootstrap和普通的HTML页面一样,定义标题都是使用标签<h1>到<h6>,只不过Bootstrap覆盖了其默认的样式,使用其在所有浏览器下显示的效果一样。为了让非标题元素和标题使用相同的样式,还特意定义了.h1~.h6六个类名。同时后面可以紧跟着一行小的副标题或使用.small

<h1>h1. Bootstrap heading副标题</h1>
<div class="h1">Bootstrap标题1<span class="small">副标题</span></div>

段落

段落是排版中另一个重要元素之一。通过.lead 来突出强调内容(其作用就是增大文本字号,加粗文本,而且对行高和margin也做相应的处理。可以使用以下标签给文本做突出样式处理:

:小号字

:加粗

:斜体

<p class="lead">以后的会感谢现在努力</p>

强调

定义了一套类名,这里称其为强调类名,这些强调类都是通过颜色来表示强调,具本说明如下:

.text-muted:提示,使用浅灰色(#999)

.text-primary:主要,使用蓝色(#428bca)

.text-success:成功,使用浅绿色(#3c763d)

.text-info:通知信息,使用浅蓝色(#31708f)

.text-warning:警告,使用黄色(#8a6d3b)

.text-danger:危险,使用褐色(#a94442)

<div class="text-muted">提示效果</div>
<div class="text-primary">主要效果</div>
<div class="text-success">成功效果</div>
<div class="text-info">信息效果</div>
<div class="text-warning">警告效果</div>
<div class="text-danger">危险效果</div>

对齐效果

在CSS中常常使用text-align来实现文本的对齐风格的设置。

其中主要有四种风格:

左对齐,取值left ;

居中对齐,取值center;

右对齐,取值right ;

两端对齐,取值justify。

为了简化操作,方便使用,Bootstrap通过定义四个类名来控制文本的对齐风格:.text-left:左对齐 .text-center:居中对齐 .text-right:右对齐 .text-justify:两端对齐。

<p class="text-left">我居左</p>
<p class="text-center">我居中</p>
<p class="text-right">我居右</p>
<p class="text-justify">网格系统的实现原理非常简单,仅仅是通过定义容器大小,平分12份(也有平分成24份或32份,但12份是最常见的),再调整内外边距,最后结合媒体查询,就制作出了强大的响应式网格系统。Bootstrap框架中的网格系统就是将容器平分成12份</p>

列表

在HTML文档中,列表结构主要有三种:

无序列表(<ul><li>…</li></ul>)

有序列表(<ol><li>…</li></ol>)

定义列表(<dl><dt>…</dt><dd>…</dd></dl>)

去点列表

class="list-unstyled"

<ul class="list-unstyled">
<li>无序项目列表一</li>
<li>无序项目列表二</li>
</ul>

内联列表

class="list-inline",把垂直列表换成水平列表,而且去掉项目符号(编号),保持水平显示。也可以说内联列表就是为制作水平导航而生。

<ul class="list-inline">
<li>首页</li>
<li>java学院</li>
<li>在线课堂</li>
</ul>

定义列表

在原有的基础加入了一些样式,使用样式 class="dl-horizontal" 制作水平定义列表 : 当标题宽度超过160px时,将会显示三个省略号。

<dl>
<dt>HTML</dt>
<dd>超文本标记语言</dd>
<dt>CSS</dt>
<dd>层叠样式表是一种样式表语言</dd>
</dl>
<dl class="dl-horizontal">
<dt>HTML 超文本标记语言</dt>
<dd>HTML称为超文本标记语言,是一种标识性的语言。</dd>
<dt>测试标题不能超过160px的宽度,否则2个点</dt>
<dd>我在写一个水平定义列表的效果,我在写一个水平定义列表的效果。</dd>
</dl>

代码

一般在个人博客上使用的较为频繁,用于显示代码的风格。在Bootstrap主要提供了三种代码风格:

(1)使用来显示单行内联代码

(2)使用<pre></pre>来显示多行块代码

样式:pre-scrollable (height,max-height高度固定,为340px,超过存在滚动条)

(3)使用来显示用户输入代码,如快捷键

单行内联代码

this is a simple code

快捷键

<p>使用ctrl+s保存</p>

多行块代码

<!-- 代码会保留原本的格式,包括空格和换行 -->
<pre>
public class HelloWorld {
public static void main(String[] args){
System.out.println("helloworld...");
}
}
</pre>
<!--
显示html标签的代码需要适应字符实体
小于号(<)要使用硬编码“<”来替代,大于号(>)使用“>”来替代
-->
<pre>
<ul>
<li>测试实体符</li>
</ul>
</pre>
<!-- 当高度超过,会存在滚动条 -->
<pre class="pre-scrollable">
<ol>
<li>...........</li>
<li>...........</li>
<li>...........</li>
<li>...........</li>
<li>...........</li>
<li>...........</li>
<li>...........</li>
<li>...........</li>
<li>...........</li>
<li>...........</li>
<li>...........</li>
<li>...........</li>
</ol>
</pre>

表格

表格样式

Bootstrap为表格提供了1种基础样式和4种附加样式以及1个支持响应式的表格。在使用Bootstrap的表格过程中,只需要添加对应的类名就可以得到不同的表格风格:

基础样式

1).table:基础表格

附加样式

1) .table-striped:斑马线表格

2) .table-bordered:带边框的表格

3) .table-hover:鼠标悬停高亮的表格

4). table-condensed:紧凑型表格,单元格没内距或者内距较其他表格的内距小

tr、th、td样式

提供了五种不同的类名,每种类名控制了行的不同背景颜色

描述

实例

.active

将悬停的颜色应用在行或者单元格上

f5f5f5

.success

表示成功的操作

dff0d8

.info

表示信息变化的操作

d9edf7

.warning

表示一个警告的操作

fcf8e3

.danger

表示一个危险的操作

f2dede

JavaSE数据库JavaScript
面向对象oraclejson
数组mysqlajax

表单

表单主要功能是用来与用户做交流的一个网页控件,良好的表单设计能够让网页与用户更好的沟通。表单中常见的元素主要包括:文本输入框、下拉选择框、单选按钮、复选按钮、文本域和按钮等。

表单控件

.form-control .input-lg(较大) .input-sm(较小)

输入框 text

.form-control

<div class="col-sm-3">
<input type="text" name="" id="" class="form-control" />
<input type="text" name="" id="" class="form-control input-lg" />
<input type="text" name="" id="" class="form-control input-sm" />
</div>

下拉选择框 select

多行选择设置:multiple="multiple"

<div class="col-sm-3">
<select class="form-control">
<option>北京</option>
<option>上海</option>
<option>深圳</option>
</select>
<select class="form-control" multiple="multiple">
<option>北京</option>
<option>上海</option>
<option>深圳</option>
</select>
</div>

文本域 textarea

<div class="col-sm-3">
<textarea class="form-control" rows="3"></textarea>
</div>

复选框 checkbox

垂直显示: .checkbox

水平显示: .checkbox-inline

<!-- 垂直显示 -->
<div>
<div class="checkbox">
<label><input type="checkbox" >游戏</label>
</div>
<div class="checkbox">
<label><input type="checkbox" >学习</label>
</div>
</div>
<!-- 水平显示 -->
<div>
<label class="checkbox-inline">
<input type="checkbox" >游戏
</label>
<label class="checkbox-inline">
<input type="checkbox" >学习
</label>
</div>

单选框 radio

垂直显示: .radio

水平显示: .radio-inline

<!-- 垂直显示 -->
<div>
<div class="radio">
<label><input type="radio" >男</label>
</div>
<div class="radio">
<label><input type="radio" >女</label>
</div>
</div>
<!-- 水平显示 -->
<div>
<label class="radio-inline">
<input type="radio" >男
</label>
<label class="radio-inline">
<input type="radio" >女
</label>
</div>

按钮

1)使用 button 实现

基础样式: btn

<button class="btn">按钮</button>

附加样式:btn-primary btn-info btn-success btn-warning btn-danger btn-link btn-default

<button class="btn btn-danger">按钮</button>
<button class="btn btn-primary">按钮</button>
<button class="btn btn-info">按钮</button>
<button class="btn btn-success">按钮</button>
<button class="btn btn-default">按钮</button>
<button class="btn btn-warning">按钮</button>
<button class="btn btn-link">按钮</button>

2)多标签支持:使用 a div 等制作按钮

a标签按钮
<span class="btn btn-success">span标签按钮</span>
<div class="btn btn-warning">div标签按钮</div>

3)按钮大小

使用 .btn-lg、.btn-sm 或 .btn-xs 就可以获得不同尺寸的按钮

<button class="btn btn-primary btn-xs">超小按钮.btn-xs</button>
<button class="btn btn-primary btn-sm">小型按钮.btn-sm</button>
<button class="btn btn-primary">正常按钮</button>
<button class="btn btn-primary btn-lg">大型按钮.btn-lg</button>

4)按钮禁用

方法1:在标签中添加disabled属性

<button class="btn btn-danger" disabled="disabled">禁用按钮</button>

方法2:在元素标签中添加类名"disabled"

<button class="btn btn-danger disabled">禁用按钮</button>

在class属性中添加disabled只是样式上禁用了,并不是真正的禁用了此按钮!

表单布局

基本的表单结构是 Bootstrap 自带的,个别的表单控件自动接收一些全局样式。下面列出了创建基本表单的步骤:

  • 向父 <form> 元素添加 _role="form"_。
  • 把标签和控件放在一个带有 class .form-group 的 <div> 中。这是获取最佳间距所必需的。
  • 向所有的文本元素 <input>、<textarea> 和 <select> 添加 class ="_form-control_" 。
水平表单

同一行显示form-horizontal

配合Bootstrap框架的网格系统

<form class="form-horizontal" role="form">
<div class="form-group">
<label for="email" class="control-label col-sm-2">邮箱</label>
<div class="col-sm-10">
<input type="email" class="form-control" placeholder="请输入邮箱"/>
</div>
</div>
<div class="form-group">
<label for="pwd" class="control-label col-sm-2">密码</label>
<div class="col-sm-10">
<input type="pwd" class="form-control" placeholder="请输入密码" />
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2">
<div class=" checkbox">
<label>
<input type="checkbox" />记住密码
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-default">提交</button>
</div>
</div>
</form>

内联表单

将表单的控件都在一行内显示form-inline

注意label不会显示,存在的意义:如果没有为输入控件设置label标签,屏幕阅读器将无法正确识别。

<form class="form-inline">
<div class="form-group">
<label for="email" >邮箱</label>
<input type="email" class="form-control" placeholder="请输入邮箱"/>
</div>
<div class="form-group">
<label for="pwd" >密码</label>
<input type="pwd" class="form-control" placeholder="请输入密码" />
</div>
<div class="form-group checkbox">
<label><input type="checkbox" />记住密码</label>
</div>
<div class="form-group">
<button class="btn btn-default">提交</button>
</div>
</form>

缩略图

缩略图在电商类的网站很常见,最常用的地方就是产品列表页面。缩略图的实现是配合网格系统一起使用。同时还可以让缩略图配合标题、描述内容,按钮等。

<div class="container">
<div class="row">
<div class="col-md-3">
<div class="thumbnail">
<img data-original="img/IMG_0131.JPG" alt="...">
<h3>高圆圆</h3>
<p>出生于北京市,中国内地影视女演员、模特。</p>
<button class="btn btn-default">
<span class="glyphicon glyphicon-heart"></span>喜欢</button>
<button class="btn btn-info">
<span class="glyphicon glyphicon-pencil"></span>评论
</button>
</div>
</div>
</div>
</div>

面板

默认的 .panel组件所做的只是设置基本的边框(border)和内补(padding)来包含内容。

.panel-default:默认样式

.panel-heading:面板头

.panel-body:面板主体内容

<div class="panel panel-success">
<div class="panel-heading">
......
</div>
<div class="panel-body">
......
</div>
</div>

BootStrap 插件

导航

使用下拉与按钮组合可以制作导航

要点:

1、基本样式: .nav 与 “nav-tabs”、“nav-pills”组合制作导航
2、分类:
1)、标签型 (nav-tabs)导航
2)、胶囊形(nav-pills)导航
3)、堆栈(nav-stacked)导航
4)、自适应(nav-justified)导航
5)、面包屑式(breadcrumb)导航 ,单独使用样式,不与nav一起使用,直接加入到ol、ul中即可,一般用于导航,主要是起的作用是告诉用户现在所处页面的位置(当前位置)
3、状态:
1)、选中状态 active 样式
2)、禁用状态: disable
4、二级菜单

标签式导航

<p>标签式的导航菜单</p>
<ul class="nav nav-tabs">
<li class="active">Home</li>
<li>SVN</li>
<li>iOS</li>
<li>VB.Net</li>
<li>Java</li>
<li>PHP</li>
</ul>

胶囊式导航

<p>基本的胶囊式导航菜单</p>
<ul class="nav nav-pills">
<li class="active">Home</li>
<li>SVN</li>
<li>iOS</li>
<li>VB.Net</li>
<li>Java</li>
<li>PHP</li>
</ul>

分页导航

分页随处可见,分为页码导航和翻页导航

页码导航:ul标签上加pagination [pagination-lg | pagination-sm]

翻页导航:ul标签上加pager

分页

<ul class="pagination">
<li>«</li>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>»</li>
</ul>

翻页

<ul class="pager">
<li>Previous</li>
<li>Next</li>
</ul>

下拉菜单

在使用Bootstrap框架的下拉菜单时,必须使用两个js

<!-- 如果要使用Bootstrap的js插件,必须先调入jQuery -->
<script data-original="js/jquery-3.4.1.js"></script>
<!-- 包括所有bootstrap的js插件或者可以根据需要使用的js插件调用 -->
<script data-original="js/bootstrap.min.js"></script>

要点:

1、使用一个类名为dropdown 或btn-group的div 包裹整个下拉框:
<div class="dropdown"></div>
2、默认向下dropdown,向上弹起加入 . dropup 即可
3、使用button作为父菜单,使用类名: dropdown-toggle 和自定义data-toggle属性
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"></button>
4、在button中 使用font 制作下拉箭头
<span class="caret"></span>
5、下拉菜单项使用一个ul列表,并且定义一个类名为“dropdown-menu
6、分组分割线: <li>添加类名“divider”来实现添加下拉分隔线的功能
7、分组标题: li 添加类名 “dropdown-header” 来实现分组的功能
8、对齐方式:
1)、dropdown-menu-left 左对齐 默认样式
2)、dropdown-menu-right   右对齐
9、激活状态(.active)和禁用状态(.disabled)

<!--使用一个类名为dropdown,默认向下dropdown,向上弹起加入 . dropup 即可-->
<div class="dropdown ">
<!--使用button作为父菜单,使用类名: dropdown-toggle 和自定义data-toggle属性-->
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
喜欢频道 <span class="caret"></span><!--下拉箭头-->
</button>
<!--下拉菜单项使用一个ul列表,并且定义一个类名为“dropdown-menu-->
<ul class="dropdown-menu"> <!--dropdown-menu-right右对齐-->
<!--分组标题: li 添加类名 “dropdown-header” 来实现分组的功能-->
<li class="dropdown-header">----科普----</li>
<li>
人与自然
</li>
<!--分组分割线: <li>添加类名“divider”来实现添加下拉分隔线的功能-->
<li class="divider"></li>
<li class="dropdown-header">----搞笑----</li>
<li>
欢乐喜剧人
</li>
<li>
快乐大本营
</li>
<li class="divider"></li>
<li class="disabled"> <!--禁用状态-->
生活大爆炸
</li>
</ul>
</div>

模态框

模态框(Modal)是覆盖在父窗体上的子窗体。通常,目的是显示来自一个单独的源的内容,可以在不离开父窗体的情况下有一些互动。子窗体可提供信息、交互等。

用法

  1. 通过 data 属性:在控制器元素(比如按钮或者链接)上设置属性 data-toggle="modal",同时设置 data-target="#identifier"href="#identifier" 来指定要切换的特定的模态框(带有 id="identifier")。
  2. 通过 JavaScript:使用这种技术,可以通过 JavaScript 来调用带有 id="identifier" 的模态框:

$('#identifier').modal(options);

实例

<h2>创建模态框(Modal)</h2>
<!-- 按钮触发模态框 -->
<button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
开始演示模态框
</button>
<!-- 模态框(Modal) -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">模态框(Modal)标题</h4>
</div>
<div class="modal-body">在这里添加一些文本</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary">提交更改</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal -->
</div>

方法

方法

描述

实例

Toggle: .modal('toggle')

手动切换模态框。

$('#identifier').modal('toggle');

Show: .modal('show')

手动打开模态框。

$('#identifier').modal('show');

Hide: .modal('hide')

手动隐藏模态框。

$('#identifier').modal('hide');

查看原文

赞 0 收藏 0 评论 0

认证与成就

  • 获得 1 次点赞
  • 获得 0 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 0 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2020-12-15
个人主页被 909 人浏览