第 2 课 Python Web 企业门户 - 框架构建
目录
2.1 Web前端基础
2.1.1 HTML基础
2.1.2 CSS基础
2.1.3 JavaScript基础
2.1.4 Bootstrap框架
2.2 后端Django框架
2.2.1 Django介绍
2.2.2 第一个Django项目
2.3 企业门户网站框架设计
2.3.1 需求概述
2.3.2 搭建项目框架
我们的教程会从头搭建一个完整的企业门户网站,而一个完整的web网站是分前端和后端的。简单来理解,前端完成网页的页面设计以及逻辑交互,后端完成数据查询、比对、渲染等操作。本教程偏重讲解后端python web框架,但是考虑到项目的整体性,我们一方面会尽可能用一些现成、好用的前端框架来完成页面设计,另一方面我们也会讲解一部分前端知识从而帮助读者快速掌握必要的前端概念,打好基础。
2.1 Web前端基础
2.1.1 HTML基础
HTML的意思是超文本标记语言(HyperText Markup Language,HTML),是一种网页文件。网页文件本身是一种文本文件,它通过标记符号来标记要显示的网页中的各个部分。浏览器按顺序阅读网页文件,然后根据标记符解释和显示其标记的内容。简单来说,HTML是一种能被浏览器识别解析,并且能够显示相应内容的语言。在Web开发中,HTML属于书写网页结构语言,是Web开发中必不可少的一门语言。
下面先看一个最简单的HTML示例。在VS Code中新建一个HTML文件(文件名后缀为.html),编辑代码如下:
<!DOCTYPE HTML>
<html>
<head>
<title>这是我的第一个网页</title>
<link href="style.css" rel="stylesheet">
<script src="index.js"></script>
</head>
<body>
<h1>你好</h1>
</body>
</html>
上述代码是最基本的一段HTML代码,其中DOCTYPE元素让浏览器知道其处理的是HTML文档,表示HTML文档的开始,紧跟其后的是HTML元素的开始标签,它告诉浏览器:从HTML开始标签<html>到结束标签</html>,所有元素内容都应作为HTML处理。head元素中的内容为HTML文档的元数据部分,HTML的元数据用来向浏览器提供页面的相关信息。另外需要引用的css和js脚本文件一般也在head中进行导入。body元素中的内容为HTML的主体,这也是HTML文档的最后一部分,body元素告诉浏览器该向用户显示文档的哪些内容,具体的包括图片、文字等。保存后用浏览器双击该文件查看效果。
HTML中通过大量元素的使用来嵌入内容。元素分为3个部分,其中有两个部分称为标签(tag),开始标签<code>和结束标签</code>。夹在两个标签之间的是元素的内容。例如上例中的“你好”是标签<h1>和</h1>的内容。两个标签连同它们之间的内容构成基本元素。HTML定义了各种各样的元素,他们在HTML文档中起着各种作用。因此,学习HTML的关键在于掌握各种HTML元素的不同含义,通俗的讲就是要知道每个元素具体有什么样的功能。HTML文档中元素之间有明确的关系。如果一个元素包含另一个元素,那么前者就是后者的父元素,反过来说,后者就是前者的子元素。一个元素可以拥有多个子元素,但是只能有一个父元素。在上面的代码中最外层的html元素包含了head元素和body元素,那么head元素和body元素就是html的子元素;反之,head和body元素的父元素只有一个,那就是html元素。同时head元素和body元素都是在html元素之下,属于同级元素,相当于辈分一样,可以称它们互为兄弟元素。而body元素中的h1元素相对于html来说,h1元素是其子元素的子元素,元素可以往下多级嵌套,这些子元素统称为html元素的后代元素
下面介绍一些基本的但是非常重要的HTML标签。读者需要了解这些标签。
- div块
div标签表示一个区块或者区域,可以把它看成是一个容器,用来把网页分块并且可以将任意的html元素置于其中,后面在项目实战过程中将会大量运用div来构建响应式网站。基本形式如下:
<div>Python Web 企业门户网站开发</div>
- span块
span标签可以表示一个小区块,比如一些文字。span和div的不同在于多个span能够在一行内显示而每个div是独占一行的。span基本形式如下:
<span>Python Web 企业门户网站开发</span>
-
h1至h6标题
h1至h6 这6个标签表示6级标题,表现出来的效果就是从h1开始文字大小逐渐变小。基本形式:
<h1>Python Web企业门户网站开发</h1>
<h2>Python Web企业门户网站开发</h2>
<h3>Python Web企业门户网站开发</h3>
<h4>Python Web企业门户网站开发</h4>
<h5>Python Web企业门户网站开发</h5>
<h6>Python Web企业门户网站开发</h6>
-
p段落
p标签是段落标签,通常用来表示一整段文字,在开发博客、新闻等文章型内容时经常会使用该标签。基本形式如下:
<p>
Python Web企业门户网站开发、Django项目实战。
</p>
-
ul 和 li 列表
ul为无序列表标签,而li为ul中的每个列表项目。这两个标签非常实用,网站制作中的导航栏、新闻列表等都可以用这两个标签来实现。基本形式如下:
<ul>
<li>这是第1条</li>
<li>这是第2条</li>
<li>这是第3条</li>
</ul>
-
i、em、strong、hr和br格式
i和em 标签表示斜体,strong标签表示加粗,hr表示一根水平分割线,br表示换行。基本形式:
<i>Python Web 企业门户网站开发实战</i>
<em>Python Web 企业门户网站开发实战</em>
<strong>Python Web 企业门户网站开发实战</strong>
<hr>
<p>Python Web<br />企业门户网站开发实战</p>
-
img图像
img标签表示图像,可以通过该标签引入图片,在实际网站开发时这个img标签经常会被使用。基本形式如下:
<img src='1.jpg' alt='图片1' title='测试图片'>
其中该标签的src属性指向图片所在路径,此路径可以是网络路径也可以是本地路径。如果是本地路径的话,就要区分是相对路径还是绝对路径。在img标签中还经常会使用两个属性:alt和title。alt表示当图片没有被正确加载的时候显示的文字,title表示当鼠标移动到图片的时候显示的文字。
-
a超链接
a标签表示超链接,一般用于指向某个网址。基本形式如下:
<a href='http://python3web.com'>百度一下</a>
(小提示)最后,这里介绍个VS Code插件,可以方便的对HTML代码进行自动对齐。打开VS Code扩展,搜索beauty,如下图所示:
然后安装第一个Beauty插件。使用时,只需要选择需要对齐的代码段落,然后右键,选择“格式化选定内容”,就可以实现自动对齐HTML代码功能。
2.1.2 CSS基础
CSS(Cascading Style Sheet),中文一般称为“层叠样式表”或“级联样式表”,它是一组格式设置规则,用于控制Web页面的外观。比如,让HTML中的某个div或者span元素背景颜色改为黑色,或者设置图片元素img的长、宽、显示位置等,这些外观的设置功能都可以通过CSS来控制。在Web前端开发中,HTML用来控制页面的内容,而CSS用来控制页面内容的显示方式。
CSS中的内容一般与HTML中的元素绑定起来,由选择符和属性组成,选择符后面跟着属性,但被一对花括号所包围。属性和值由冒号分隔,每个属性声明以分号结尾。典型的CSS样式设计代码:
body {
background-color:white; /* 将背景色置为白色 */
color:black; /* 将前景色置为黑色 */
}
上例中对HTML文件中的body元素进行外观设置,使得body的背景颜色为白色,前景颜色(一般指字体、边框等)为黑色。
为了能够设置HTML中的元素外观,需要在HTML中引入CSS,具体的有三种引入方式:
(1)内联样式表:将CSS样式设置代码内嵌到HTML文件的<style>标签中。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
#box {
width: 100px;
height: 100px;
background: red;
}
</style>
</head>
<body>
<div id="box"></div>
</body>
</html>
上述代码通过内嵌CSS方式,使得body中id号为box的<div>元素宽、高均设置为100像素,背景颜色设置为红色,保存该HTML文件并用浏览器打开可以查看效果。
(2)链接样式表:将一个外部样式通过<link>标签链接到HTML文件中。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div id="box"></div>
</body>
</html>
上述代码对div元素box的控制写在一个额外的CSS文件style.css中并通过<link>标签的引入实现对box元素的样式控制。
(3)行内样式表。将样式表直接加入到HTML文件的元素设置中。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<div id="box" style="width:100px;height:100px;background:red;"></div>
</body>
</html>
上述代码中,直接在box元素的style属性中进行CSS样式设置。当然,可以采用这种方式对整个的页面元素进行设置,但是这种方式编写的CSS不具有复用性,只能针对当前控制的页面元素,在开发实际项目的过程中这种方式采用的相对较少。
下面介绍下CSS的选择器。在CSS中,选择器是一种模式,用于选择需要添加样式的元素,即通过选择器可以在HTML中找到需要更改外观的元素。下面列举一些经常使用的选择器并介绍其基本的使用方法。
(1)ID选择器
ID选择器采用符号#来进行元素选择。ID通常表示唯一值,因此,ID选择器在CSS 中通常只出现一次。ID选择器的一般形式如下:
#box{
background: red;
}
上述代码会将id号为box的页面元素的背景置为红色。
(2)类选择器
类(class)选择器就是将相同类型的元素进行分类定义,分类定义的好处就是能够复用。在类名前面加符号”.”,表示定义一个类选择器,引用的时候在标签后面加class引用。类选择器基本形式
.box{
background: red;
}
上述代码会将id号为box的页面元素的背景置为红色。
(3)标签选择器
标签选择器就是直接使用HTML标签名称作为CSS选择器的名称,这种方式会影响HTML中所有此标签的样式。
div{
background: red;
}
上述代码会影响到HTML中所有使用div标签的地方,使得其背景颜色变为红色。
(4)多元素选择器
当几个元素需要设置相同的CSS风格时,可以使用多元素选择器。选择多个元素的时侯,用逗号隔开。多元素选择器基本形式如下:
div,span{
background: red;
}
上述代码会使得HTML中所有div和span标签的背景均为红色。
(5)后代选择器
后代选择器作用于父元素下面的所有子元素,其级联层次按照HTML中的元素结构进行查找。后代选择器基本调用形式如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style>
#box p {
color: red;
}
</style>
</head>
<body>
<div id="box">
<p>python web企业门户网站开发</p>
</div>
</body>
</html>
上述代码通过内联样式表进行CSS设置,首先找到<body>中id号为box的<div>元素,然后针对<div>元素中所有的<p>元素将其颜色设置为红色。后代选择器之间使用空格进行元素的递进选择。
CSS提供了很多针对HTML元素的属性可供更改,包括颜色、长、宽、边框大小、背景图片等。合理的使用CSS属性进行网页控制和布局,可以制作出美观的网站给用户浏览。常见属性包括颜色color、边框border、背景background、字体font等,具体属性的使用方法我们后面在项目实战部分进行讲解。
2.1.3 JavaScript基础
JavaScript是专门用于Web前端的动态脚本语言,主要作用是通过操作HTML元素动态的修改页面。JavaScript的运行环境非常简单,一般的浏览器都支持JavaScript,编写的JavaScript代码可以直接在浏览器中运行,无需安装其它的编译器。
JavaScript代码的引用方式有两种,第一种是直接通过<script>标签将代码嵌入到HTML文件中,如下所示:
<!DOCTYPE HTML>
<html>
<head>
<title>JavaScript示例</title>
</head>
<body>
<script type="text/JavaScript">
alert("你好!");
</script>
</body>
</html>
上述代码在文件类型申明中使用type="text/JavaScript"语句告诉浏览器该段落是一个JavaScript代码段。在<script>元素中通过alert函数弹出提示语句对话框,该函数功能类似于Python的print函数,主要用来进行显示结果。
第二种引用方式需要将JavaScript代码单独的保存为一个后缀为js的文件,然后再在HTML中引入,具体引用形式如下:
<!DOCTYPE HTML>
<html>
<head>
<title>JavaScript示例</title>
<script type="text/JavaScript" src="index.js"></script>
</head>
</html>
JavaScript与Python一样,属于高级解释型语言,它的语法简洁,使用方便。作为一门语言,JavaScript拥有自己特有的语法,本书重点在于Python语言的运用,因此无法对JavaScript进行全面的阐述,有兴趣的读者可以查找其它资料深入学习。尽管不能详细介绍完JavaScript,但是由于现在出现了很多成熟的前端框架,这使得很多后端开发人员可以一定程度上“避开”JavaScript,使用现成的前端框架,一样可以实现自己需要的效果。
下面我们介绍一款目前国内外广泛使用的前端框架Bootstrap,这也是支撑我们这个项目的很重要的一个工具。
2.1.4 Bootstrap框架
Bootstrap是由Twitter的设计师Mark Otto和Jacob Thornton合作开发的,基于HTML、CSS、JavaScript的CSS/HTML框架,它简洁灵活,使得Web开发更加快捷,Bootstrap一经推出便颇受欢迎。Bootstrap同时还兼顾了响应式网站的设计理念,使用Bootstrap可以开发全响应式网页,无论是使用手机、平板电脑还是普通个人电脑,浏览网站内容时所有的元素都可以自适应的呈现。因此,国内外很多开发人员都使用Bootstrap来开发适合各种设备浏览的页面,避免大量的因为兼容性而导致的重复劳动。目前Bootstrap的最新版本是4.0,国内使用较多的是3系列,本书教程也采用Bootstrap 3系列版本,这也是目前性能最稳定的版本。
(1)Bootstrap下载和使用
Bootstrap本质上是一套js、css、fonts字体样式库文件,可以从Bootstrap中文官网上进行下载,下载网址:https://v3.bootcss.com/getting-started/#download。Bootstrap提供了三种不同版本可供下载,如下图所示:
由于后面的实战项目需要对Bootstrap中的组件进行二次开发,因此为了方便组件定制,这里推荐选择“下载源码”。下载完成后解压,找到其中的dist文件夹,该文件夹中包含三个子文件夹:css、fonts和js。上述三个子文件夹包含了一些css、js以及字体文件,这些文件即为所需的Bootstrap框架的基本配置文件,其中已经封装好了大量Web开发可直接调用的组件和字体库。
Bootstrap中文官网给出了很多详细的使用案例,所有的组件都可以通过该官网找到对应的使用方法。下面结合官网样例以及下载的Bootstrap作一个简单使用介绍,读者也可以从官网自行查找并学习其它相关案例。
首先,新建一个文件夹名为BootstrapDemo,然后把下载下来的Bootstrap中的css、js和fonts三个子文件夹放入BootstrapDemo中。用VS Code打开BootstrapDemo文件夹,在该文件夹下新建一个index.html文件用于编写网页。
在index.html中编写一个基本的HTML页面,并且在<head>标签部分引用三个必要的Bootstrap文件,分别为:bootstrap.min.css、jquery.min.js、bootstrap.min.js。其中需要注意的是jquery.min.js文件,由于下载的Bootstrap中并没有包含该文件,因此需要从外部引入。具体的,index.html中代码如下:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap简单示例</title>
<link href="css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js">
</script>
<script src="js/bootstrap.min.js"></script>
</head>
<body>
</body>
</html>
下面我们着重分析下上面的这段代码:
- 第1行代码用于申明这是一个标准HTML5网页。HTML5是HTML最新的修订版本,HTML5的设计目的是为了在移动设备上支持多媒体,增加了许多的描述型标签。
- 第2行用于表示支持中文。在head部分使用了一些<meta>标签,这些meta标签可提供有关页面的元信息。
- “utf-8”表示一种字符编码格式,用于告知浏览器此页面属于utf-8中文编码,让浏览器做好“翻译”工作。
- http-equiv="X-UA-Compatible"用来避免制作出的页面在IE8下面出现错误。
- intial-scale用于设置页面首次被显示时可视区域的缩放级别,取值1.0则使页面按实际尺寸显示,无任何缩放;
- 在<head>最后引入Bootstrap的3个必要文件,其中jquery.min.js文件是通过外网引用的方式导入,如果希望以本地引用的方式导入,可以通过浏览器访问该网址,然后将内容保存为独立的jquery.min.js文件,然后放置于项目的js文件夹下面,最后再采用本地引用方式导入;
上面的代码是一个基本框架,通过上面的代码我们准备好了Bootstrap环境,下面就可以在html的<body>部分使用Bootstrap各种精美的组件。下面我们举个简单例子。我们在<body>标签部分添加代码如下:
<body>
<div class="alert alert-success" role="alert">Python Web实战</div>
<div class="alert alert-info" role="alert">Python Web实战</div>
<div class="alert alert-warning" role="alert">Python Web实战</div>
</body>
然后保存修改的html文件。接下来我们用浏览器打开我们刚才的index.html文件,正常情况下效果如下所示:
上面我们就直接使用了bootstrap现成的带颜色的面板 。
其他相关组件,读者可以从Bootstrap官网参照示例进行测试,本书不再专门讲解bootstrap组件。
(2)Bootstrap栅格布局
学习Bootstrap有一个知识点很重要,这个直接影响我们后面的门户网站页面设计,那就是Bootstrap特有的栅格布局。
Bootstrap提供了一套响应式、移动设备优先的流式栅格系统,随着屏幕尺寸的增加,系统会自动分为12列。一般的,针对现有的移动设备:手机、平板以及桌面浏览器等,Bootstrap提供了4种分辨率规模,分别是col-xs(小屏幕手机)、col-sm(平板)、col-md(普通桌面显示器)、col-lg(大型桌面显示器)。比如,下面的代码演示了如何在桌面显示器和手机上分别以两种不同的适配形态进行展示;
<body>
<div class="alert alert-success col-md-6 col-xs-12" role="alert">
Python Web实战
</div>
<div class="alert alert-info col-md-6 col-xs-12" role="alert">
Python Web实战
</div>
</body>
上述代码调用了两个提示框,通过添加类col-md-6表示在普通桌面显示器下该<div>占6格,因此两个提示框各占6格正好铺满一行,效果如下图所示:
如果将浏览器窗口缩小或者采用手机浏览,此时类样式col-xs-12起作用,使得该<div>占整个一行,最终两个提示框会分行显示,如下图所示:
采用Bootstrap的栅格系统可以方便的同时开发出适合桌面浏览器和移动设备的网站,实现一套代码多种设备适配。另外,Bootstrap的栅格系统使得网页的布局更加简单,只需要将各个组件堆叠到对应的div中,然后通过栅格系统实现每个div的位置控制。
简单来理解,Bootstrap的栅格布局就是通过简单的类似“col-md-6”这样的CSS类样式,可以方便的对页面进行拆分布局,同时可以实现电脑和手机上不同的展示效果,电脑屏幕大,因此使用展开的样式,手机屏幕小,因此使用折叠的样式。
到这里,我们前端的基础概念知识就讲完了。当然,我们这里只是挑选了部分经常使用到的前端知识进行讲解,方便我们后面实战开发,读者应该尽可能的牢记这些知识点,后面在实战开发部分我们会经常使用到这些概念。
2.2 后端Django框架
前面我们花了大量的精力讲解Web前端基础知识,接下来我们正式开始讲解本项目的重头戏—后端Django框架。
2.2.1 Django介绍
Web开发是Python应用领域的重要部分,也是工作岗位比较多的领域。无论是对Python Web开发有兴趣,还是打算开始学习使用Python做Web开发,或者有工作需要,要做Web服务、自动化运维、数据的图形化展示等,学习一门基于Python的Web开发框架是必修课。Python作为当前最热门、也是最主要的Web开发语言之一,在其二十多年的历史中出现了数十种Web框架,比如Django、Tornado、Flask、Twisted、Bottle、Web.py以及近几年出现的fastapi等,它们有的历史悠久,有的发展迅速,还有的已经停止维护,其中Django是众多框架中使用者最多、涵盖面最全的框架。Django采用Python语言编写,它本身起源于一个在线新闻站点,于2005年以开源的形式被发布,任何人、任何商业公司均可以免费使用。
具体的,采用Django开发Web应用有如下优势:
- Django是一个由Python写成的开源Web应用框架,因此继承了Python语言具有的简洁、轻量等特性,拥有丰富的第三方组件,适合快速构建项目;
- Django拥有强大的数据库功能。几行代码就可以拥有一个丰富、动态的数据库操作接口,通过简单的配置就可以轻松切换数据库;
- 自带强大的后台管理功能。Django建立项目的同时即拥有一个现成且强大的后台管理系统,不需要写额外的代码就可以方便的以管理员身份对数据信息进行操作;
- 具有优秀的模板系统用于控制前端逻辑。Django的模板系统设计简单,容易扩展,代码和样式分开设计,使得项目结构更清晰;
- 类似热插拔的App应用理念。热插拔是指当Django项目中某个应用功能不需要了,可以直接删除,需要的应用功能则可以直接拿来使用,各个应用相对独立,不影响项目的整体架构,应用的添加和删除操作非常方便;
除了上述优势外,Django还拥有优秀的缓存、错误提示等功能,这些优势使得Django在众多Web应用框架中脱颖而出,成为当前使用人数最多的Python Web框架。
2.2.2 第一个Django项目
(1)安装Django
Django的安装与一般的Python工具包安装一样,只需要在命令窗口中通过pip install来安装即可。具体的,可以在VS Code的终端(TERMINAL)中输入下述命令实现在线下载和安装:
pip install django==3.2.7
本项目采用的是最新的Django 3.2.7版本,目前Django已经更新到3系列,其与1和2系列最大的不同在于项目中路由的设置方式有明显的差异,但是这些差异可以通过修改路由设置来兼容。另外,Django还引入了异步机制 ,可以实现异步web开发。考虑到今后的发展趋势,本项目全部更新到最新的Django3来开发,后面如果有较大的版本更动(例如出现了Django4),本文也会尽快更新到最新版。
同其它工具包卸载方式一样,Django的卸载可以通过下述命令来实现:
pip uninstall django
(2)创建Django项目
本节将会阐述如何创建一个Django项目。打开VS Code,在TERMINAL终端中通过cd命令切换到某个项目目录(打开VS Code后默认的工作目录是上一次关闭前的目录,所以如果要创建新的项目,需要切换目录)。
使用下面的命令来创建项目:
django-admin startproject welcome
通过上述命令后,可以看到已经在项目目录下面创建了一个名为welcome的文件夹,里面包含了一些自动创建好的项目文件。
接下来需要在VS Code中导入前面创建的项目,依次单击菜单栏File→Open Folder命令,找到创建的welcome文件夹(注意,在welcome文件夹下面还有一个同名的welcome子文件夹,这里打开的是外层的父文件夹),打开后VS Code的文件管理器会同步显示当前所选文件夹内的所有子文件夹和文件,如下图所示:
在当前工作目录下有一个manage.py文件以及一个与项目名字相同的welcome子文件夹。manage.py文件作为项目的主文件(类似于C++的main文件),用来执行与项目相关的一些重要命令,例如项目的启动、数据库的同步、后台管理员的创建、静态文件的迁移等等。在welcome子文件夹下有几个Python文件,下面对这些文件做基本介绍:
- __init__.py:标识文件,可以是个空文件。主要用来表明当前该文件所在的文件夹是一个Python包,在这里的作用是声明welcome子文件夹为一个独立的模块;
- settings.py:整个项目的全局配置文件。各种应用、资源路径、模版等配置均在此文件中设置;
- urls.py:网络访问的页面映射文件。创建的Web项目下所有的页面路由都需要在该文件中配置,否则在访问的时候会找不到对应的页面;
- wsgi.py:全称是web server gateway interface,即网络服务器的网关接口。在这里是指Python应用与Web服务器交互的接口,一般不需要做任何修改;
上述四个文件中需要重点关注settings.py和urls.py文件,这两个文件是项目中经常需要修改和编辑的文件。
创建项目完成后可以直接启动项目来查看项目是否创建成功。具体的,在终端中输入下述命令:
python manage.py runserver
出现下图所示效果说明项目启动成功:
打开浏览器,输入网址:127.0.0.1:8000,如果出现下图所示结果说明项目创建成功:
最后可以在终端中通过Ctrl+c组合键来关闭项目运行。
(3)创建应用
Django的一个重要优势就是支持类似热插拔的app应用。举个例子,如果把网站的登录功能看做是一个单独应用的话,那么如果想在网站中使用登录功能只需要通过简单的配置添加这个应用。应用是可以被其它Django项目重复使用的。
上一小节所创建的项目仅仅是一个Web项目的外壳,为了能够满足特定的功能需求需要创建特定功能对应的应用,本小节为了演示效果将创建只用来显示一个欢迎页面的应用。接下来在welcome项目下创建一个名为firstApp的应用,终端中输入下述命令:
python manage.py startapp firstApp
可以看到在文件管理器中多出了一个名为firstApp的文件夹,展开该文件夹可以看到如下图所示的几个Python文件:
这是创建完一个Django应用后自动生成的一些文件,下面对这些文件的作用做一些说明:
- __init__.py:标识文件,可以是个空文件,用来表明当前创建的firstApp文件夹是一个Python模块;
- admin.py:管理员配置文件,主要是用来注册一些数据库中的模型到后台管理模块中。Django给每个项目提供了一个强大的后台管理系统,为了能够在后台管理系统中管理数据库中的数据,需要通过配置admin.py文件来确认哪些数据信息可以被后台管理系统管理;
- apps.py:应用的配置文件,一般情况下不需要修改;
- models.py:数据库文件,用来管理数据库中的模型数据;
- tests.py:测试文件,在这里可以对应用作一些测试;
- views.py:视图文件,对于每个访问的实际处理操作都在这个文件中编写,在这个文件中定义了每个访问/路由的处理函数,每个访问与哪个函数绑定则由urls.py文件配置;
- migrations:数据库迁移文件夹,在执行数据库迁移的时候会产生一些中间结果,这些结果就存放在该文件夹中;
上述几个文件需要重点关注的是:views.py、models.py和admin.py文件,这是我们后面一直需要编辑的文件。
创建完应用后我们需要将其添加到项目中。打开welcome子文件夹中的settings.py文件,找到INSTALLED_APPS字段,然后在该字段末尾添加一行代码将firstApp应用包含进来即可:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'firstApp', # 新添加的应用
]
到这里应用就创建完了,并且插入到了项目中。
(4)制作访问页面
首先在创建的firstApp应用下创建一个templates文件夹用来存放网站页面。具体的,在firstApp文件夹上右键选择New Folder,新建的文件夹重命名为templates(注意django项目会自动寻找templates文件夹下面的页面资源,所以这个文件夹名字不要写错)。然后右键templates文件夹选择New File新建一个文件,文件命名为index.html。最终完整的项目目录结构如下图所示:
在VS Code中打开index.html文件,在该文件中编辑输入下面的代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>我的第一个页面</title>
</head>
<body>
<h1>欢迎</h1>
</body>
</html>
这是一个最基本的Web页面,在该页面中指定了页面的标题为“我的第一个页面”,页面内容显示“欢迎”字样。保存该文件,可以用浏览器先打开一下这个文件查看具体的效果。
在编写HTML代码时出现排版格式混乱的情况,这里推荐在VS Code中安装beauty插件用于快速对html代码内容进行排版,插件如下图所示:
具体操作时在代码编辑区按Ctrl+a组合键选中所有内容(也可选中部分内容),然后右键选择“格式化选定内容”即可实现自动对齐排版。
(5)编写视图处理函数
首先结合之前阐述的项目结构,梳理一下Web访问的基本流程:
- 用户在浏览器中输入网址(http://127.0.0.1:8000)访问welcome网站;
- 服务器收到浏览器发来的访问请求,解析请求后根据urls.py文件中定义好的路由,在views.py文件中找到对应的访问处理函数;
- 访问处理函数开始处理请求,然后返回用户想要浏览的网页内容;
本小节按照上述流程开始编写视图处理函数。打开firstApp应用下的views.py文件,编辑代码如下:
from django.shortcuts import render
# 创建视图处理函数
def home(request):
return render(request, 'index.html')
上述代码第一行引入了Django提供的渲染页面的函数render,该函数可以将网页内容转换成符合网络传输的二进制文件。然后定义了一个home函数,该函数有一个参数request,这个参数就是用户的请求参数,该参数封装了用户的所有请求信息,这里暂时对它不作处理。home函数收到请求后返回index.html页面内容。有些读者会疑惑,为何在home.html页面前没有加上templates目录,这是因为Django会自动的在每个应用下查找名为templates文件夹下的页面资源。
(6)配置访问路由url
url是Web服务的入口,用户通过浏览器发送过来的任何请求,都是发送到一个指定的url网址,然后被响应。在Django项目中编写路由,就是向外暴露Web接收哪些url对应的网络请求,除此之外的任何url都不被处理,也没有返回。通俗地理解,url路由就是Web服务对外暴露的访问接口。
具体的,welcome子文件夹下的urls.py文件用来绑定每个访问请求对应的处理函数。其中,urlpatterns即为配置访问路由的字段。接下来对urls.py文件进行编辑,使得访问根网址时即可返回index.html页面。具体编辑代码如下:
from django.contrib import admin
from django.urls import path
from firstApp.views import home # 导入新添加的视图函数
urlpatterns = [
path('admin/', admin.site.urls),
path('', home, name='home'), # 添加新的路由
]
在第3行引入了前面创建的home函数,该函数位于firstApp应用的views.py文件中,这里注意下Python导入包的写法,使用from ... import ...的形式,表示从某个模块中导入某个函数。在urlpatterns字段中有两个路由,第一个路由是创建Django项目时默认提供的,是访问后台管理系统时对应的路由。第二个路由需要手动添加,即访问欢迎页面的路由。路由匹配采用了Django 3系列提供的path函数,这里的意思是将当前访问的根网址直接映射到home函数进行处理。
(7) Web启动、关闭
前面几小节已经完成了Django项目和应用的创建,并且将应用添加到了项目,然后制作了需要访问的HTML页面,对该页面的访问请求进行了路由配置,也对路由对应的视图处理函数进行了处理,至此已经完成了一个基本的web应用的开发。接下来可以启动该项目查看最终效果。
在终端中输入下面的命令启动项目:
python manage.py runserver
默认启动页面网址为127.0.0.1:8000。启动成功后即可采用浏览器进行访问。
效果如下图所示:
最后按Ctrl+c组合键可以停止项目的运行。
上述项目的启动本质上是采用了Django提供的一个轻量级的Web开发服务器进行项目部署,旨在开发的过程中快速的查看页面效果而不需要花费额外时间进行繁琐的配置。当代码有改变的时候,开发服务器会自动重启。但是在实际操作过程中有一些特定的操作该服务器并不能捕捉到,这时就需要手动重启。总体来看,开发服务器适合单机调试,在项目开发完成后需要将Web应用部署在生产服务器上才能够适合一般网站并发、稳定的访问需求。本课程最后会详细阐述如何在Windows操作系统的IIS服务器上进行项目部署。
通过本小节的学习,相信读者已经对Django项目开发的基本流程有了一定的了解。后面会在此基础上进行更深入的学习和实战。
2.3 企业门户网站框架设计
接下来我们将以一个完整的企业门户网站为例,详细阐述基于Python Web的网络应用开发过程。具体的,将使用Django框架实现相关功能。另外,考虑到项目的完整性,对Web前端页面设计也会同步进行阐述。本项目开发的企业门户网站案例已按照最后一节教程部署在百度云服务器上,读者可以访问http://python3web.com查看整个网站的实现效果。需要注意的是,本项目所开发的企业门户网站仅作为示例教程使用,用于教学需要,所有网站内容包括企业名称、新闻动态、产品等均为虚构内容,读者学习完本教程后可以根据自己的实际需求进行修改、二次开发以方便定制化扩展。本课程所有内容开源、免费。
2.3.1 需求概述
企业门户网站的建设是加强企业与外界联系的一个重要方式,同时也是展现企业形象,提高企业的社会影响力的一种有效方式。因此,企业门户网站建设在企业发展的过程中具有十分重要的作用。
本书拟开发一个科技型企业门户网站,企业名称为:恒达科技,具体包括:首页、公司简介、新闻动态、服务支持、产品中心、科研基地、人才招聘共7个模块,每个模块可能包含两至三个子模块用于进一步细分功能。各模块及其子模块结构如下图所示:
下面对每个模块需求和功能进行简要介绍:
- 科研基地:该模块主要用于展示企业科研基地相关内容,包括科研基地的文字描述和图片等,该模块功能较为单一,仅包含一个页面,并以静态页面形式提供访问和浏览;
- 公司简介:包含两个子模块,分别是企业概况和荣誉资质。企业概况用于对企业进行简短的展示,包括说明文字和图片,用以展示企业的历史、核心产品、经营理念等。荣誉资质子模块主要以展报形式罗列企业历年来获得的荣誉,该模块随着企业发展,需要动态的增加相关内容。因此,为了方便管理员后期编辑网站内容,需要将该页面内容与数据库进行绑定,后期可以动态的添加荣誉信息;
- 产品中心:包含三个子模块,分别是机器人、智能监控和人脸识别,对应企业的三大主流产品。用户浏览产品时通过各个子模块链接切换可以按类别对产品进行浏览。因此,产品中心模块实现时需要能够从后台数据库按类型获取数据并进行页面渲染;
- 新闻动态:新闻动态模块包含三个子模块,分别是公司要闻、行业新闻和通知公告。与产品中心模块类似,用户可以通过各个子模块链接按新闻类型切换到指定子模块进行浏览。新闻内容以图文形式进行展现,并且管理员可以自定义图片和文字的格式;
- 人才招聘:该模块包含两个子模块,分别是欢迎咨询和加入恒达。欢迎咨询子模块主要用于展示企业联系人信息以及企业地理位置,需要在实现时嵌入百度地图以方便浏览者查找位置。欢迎咨询子模块用来为企业招聘提供一个互动渠道,招聘员在网站上发布招聘职位并显示在该子模块页面上,应聘者浏览该页面并通过该页面上的表单提交个人信息;
- 服务支持:该模块包含两个子模块,分别是资料下载和开放平台。资料下载子模块用于为用户提供资料下载链接,用户通过这些链接可以下载该企业的相关产品数据,包括驱动、说明文档、SDK开发包等。开放平台模块作为一个展示企业科技产品的模块,可以提供在线的人工智能算法支持,以API接口方式让用户体验产品;
- 首页:该模块作为一个企业门户网站的入口模块具有非常重要的作用,需要能够全方位的展示企业各版块功能,同时需要兼具美观、清晰的特性。另外,作为一个集成模块,首页需要调用其它模块的相关数据信息,并能够对数据进行过滤和排序;
项目效果图如下:
整体网站的功能读者可以先访问http://python3web.com自行体验,然后再进入后面的开发教程,这样可以加深各模块内容的理解,为后面的开发做好准备。下一节将进入具体的开发环节。
2.3.2 搭建项目框架
确保按照前面的教程准确安装了python和django。接下来打开VS Code,在终端中通过cd命令切换到希望创建项目的目录位置,然后输入下述命令创建一个名为hengDaProject的Django项目:
django-admin startproject hengDaProject
这样我们就把项目创建好了。接下来我们的教程会不断的对这个项目进行功能的添加和完善。
(1)文件结构设计
前面的章节中我们使用django初步接触了一个项目雏形,但是该实例仅有一个访问页面,因此,只需要建立一个应用即可完成需求功能。但是在实际情况中,一个完整的网站项目拥有较多的访问页面和多种不同功能的应用模块。如果将所有的页面访问和逻辑实现全部放在一个应用下进行开发那么会造成项目的冗余以及结构的混乱,使得项目后期维护和扩展变得异常困难。Django提供了一种多应用机制,即一个Django项目可以包含多个应用,每个应用可以实现一定的功能,或者每个应用对应部分访问内容。这样做的好处很明显,可以进一步精炼、浓缩项目功能。
根据前一节阐述的门户网站需求,可以对整个网站的功能有一个清晰的了解。针对“恒达科技”这个门户网站需求可以发现,每个页面下基本都有2~3个二级子页面,比如“公司简介”下有“企业概况”和“荣誉资质”两个子页面,“产品中心”下有“家用机器人”、“智能监控”和“人脸识别”三个子页面。在这种情况下,为了清晰的表述项目结构,一种便捷有效的结构设计方法即将每一个一级页面看作一个功能应用,具体的可以分为:“首页”、“公司简介”、“新闻动态”、“产品中心”、“服务支持”、“科研基地”、“人才招聘”共七个应用,这样每个应用下都只需要开发2~3个相似的子页面即可。采用这种方式的好处在于后期开发其它类似的项目可以重复利用这些功能模块,只需要在项目中简单的配置即可。接下来,按照上述结构思路为每个页面建立应用。
我们打开VS Code,打开刚才创建的hengDaProject目录下面,然后在VS Code中打开终端。
接下来以“首页”模块为例,在终端中输入下述命令创建一个名为homeApp的应用:
python manage.py startapp homeApp
接下来按照同样方法创建其它模块对应的应用,依次输入命令:
python manage.py startapp aboutApp
python manage.py startapp newsApp
python manage.py startapp productsApp
python manage.py startapp serviceApp
python manage.py startapp scienceApp
python manage.py startapp contactApp
通过上述命令依次创建“公司简介”(aboutApp)、“新闻动态”(newsApp)、“产品中心”(productsApp)、“服务支持”(serviceApp)、“科研基地”(scienceApp)、“人才招聘”(contactApp)这几个功能应用。所有应用创建完成后项目结构如下图所示:
接下来在项目根目录下创建templates文件夹,该文件夹用于存放各个应用共享的模板文件,此处一般指用于共享和继承的html模板文件。通常门户网站各个功能页面具有统一的风格,即网页头部、导航栏、尾部等内容一般是相同的,因此可以将这些相同的内容编辑成模板文件,其它功能页面在开发的过程中可以继承该模板文件,然后通过少量代码的修改即可实现页面的复用,这种方式可以极大的提高开发效率。Django的模板概念将会在后面一节课程进行介绍。
另外,为了能够使得多个应用共享静态资源文件,在项目根目录下创建static文件夹,在该文件夹中分别建立css、fonts、img、js这四个子文件夹,分别用来存储项目共享的样式文件、字体库文件、图片文件和JavaScript代码文件。由于本书采用的是Bootstrap前端框架,因此按照前面介绍的方法,将Bootstrap对应的配置文件分别导入到各个对应的项目文件夹中。
接下来我们在css文件夹中额外添加一个自定义的style.css文件,该文件并不是Bootstrap提供的文件,而是本项目为了定制化HTML样式单独建立的css文件。尽管可以采用Bootstrap框架完成页面的布局,但是依然有很多组件需要细微的调整,此时就需要通过在style.css文件中编写代码覆盖Bootstrap的基础样式来实现。
此处还有一个重要的文件我们需要引入到我们的项目,就是jquery.min.js文件 。前面我们在介绍Bootstrap的时候我们通过外部引入的方式导入了这个文件,后面我们想把这个文件放在本地,那怎么办呢?办法很简单,访问对应的文件地址:
https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js,然后按"ctrl+s"保存页面文件即可。然后我们把这个下载好的jquery.min.js文件放置在项目的js文件夹下面。
最后,给出hengDaProject项目完整的文件结构图,如下图所示:
(2)多级路由配置和访问
本节学习Django的多级路由配置和访问,即如何在大型项目中合理的设计每个访问页面对应的路由。在前面章节中已经接触过Django的路由配置,基本配置方法是在urls.py文件中通过path函数将路由和视图处理函数进行绑定,使得访问时能够正常解析路由并使用绑定的视图函数进行处理,基本形式如下:
path('home/', home, name= 'home'),
path函数接收的第一个参数是相对访问路由,如果项目部署在本地8000端口时,此时对应的访问网址为http://127.0.0.1:8000/home。第二个参数即指定绑定的视图函数。第三个参数用于在模板中进行逆向解析,Django模板的使用在下一节课程中详细介绍。以上配置path路由的过程相对简单,适用于小规模Django项目。当项目规模较大、具有较多的路由时,此时如果将所有路由依然放置在同一个urls.py文件中,会使得路由管理显得混乱、逻辑不清晰。一种比较好的解决方案就是将与各个应用相关的路由放置在各个应用文件夹下,每个应用单独管理一个urls.py文件。例如,“公司简介”模块下有一个“企业概况”页面,如果按照单层路由进行设计,其对应的路由形式为:
path('survey/', survey, name= 'survey')
如果希望将上述路由置于aboutApp应用下面,那么就需要定义二级路由。一级路由指定路由所在的应用app,在项目根路由文件urls.py中进行申明,形式如下:
path('aboutApp/', include('aboutApp.urls'))
path函数第一个参数用来匹配应用对应的前缀,即如果想要访问aboutApp应用下的路由,在根网址后都必须加上aboutApp前缀。path第二个参数用来接收由include指定的二级路由对应的路由文件。
二级路由可以在应用中创建一个urls.py文件,然后将二级路由与视图函数进行绑定即可。下面以“首页”homeApp和“公司简介”aboutApp两个应用为例,具体阐述如何配置多级路由并且实现访问。尽管前面已经创建了7个应用,但是所有应用并没有插入到项目中。因此,首先将homeApp和aboutApp两个应用插入到项目中来。打开hengDaProject文件夹下的settings.py文件,找到INSTALLED_APPS字段,在该字段末尾添加应用:
INSTALLED_APPS = [
...其它应用...
'homeApp', # 添加"首页"应用
'aboutApp', # 添加"公司简介"应用
]
接下来需要实现每个应用对应的页面访问。此处为了快速测试功能,暂时不对前端进行设计,只让每个页面显示不同的字符串即可,即访问首页时页面出现“首页”字符,访问企业概况时页面出现“企业概况”字符,同样访问荣誉资质页面时出现“荣誉资质”字符。
Django提供了HttpResponse函数用来直接通过代码生成页面内容并返回给前端浏览器渲染。具体的,编辑homeApp文件夹中的views.py文件,代码如下:
from django.shortcuts import render
from django.shortcuts import HttpResponse
def home(request):
html = '<html><body>首页</body></html>'
return HttpResponse(html)
上述代码首先从django包的shortcuts模块中导入HttpResponse函数,然后定义了首页路由的视图处理函数home。home函数以request为接收参数,通过调用HttpResponse函数返回一个HTML字符串给前端进行显示。这里将HTML代码硬编码在Python代码中,以字符串的形式进行返回。
接下来对“首页”路由进行配置。尽管本项目将首页也作为一个独立的应用进行设置,但是首页的路由比较特殊,一般情况下,网站的根访问路径对应网站首页,即类似访问http://127.0.0.1:8000/即可浏览首页,无需定位到某个具体的应
上一篇: java 开放源码企业门户网站
下一篇: 数据类型的确定方法
推荐阅读
-
SSM三大框架基础面试题-一、Spring篇 什么是Spring框架? Spring是一种轻量级框架,提高开发人员的开发效率以及系统的可维护性。 我们一般说的Spring框架就是Spring Framework,它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发。这些模块是核心容器、数据访问/集成、Web、AOP(面向切面编程)、工具、消息和测试模块。比如Core Container中的Core组件是Spring所有组件的核心,Beans组件和Context组件是实现IOC和DI的基础,AOP组件用来实现面向切面编程。 Spring的6个特征: 核心技术:依赖注入(DI),AOP,事件(Events),资源,i18n,验证,数据绑定,类型转换,SpEL。 测试:模拟对象,TestContext框架,Spring MVC测试,WebTestClient。 数据访问:事务,DAO支持,JDBC,ORM,编组XML。 Web支持:Spring MVC和Spring WebFlux Web框架。 集成:远程处理,JMS,JCA,JMX,电子邮件,任务,调度,缓存。 语言:Kotlin,Groovy,动态语言。 列举一些重要的Spring模块? Spring Core:核心,可以说Spring其他所有的功能都依赖于该类库。主要提供IOC和DI功能。 Spring Aspects:该模块为与AspectJ的集成提供支持。 Spring AOP:提供面向切面的编程实现。 Spring JDBC:Java数据库连接。 Spring JMS:Java消息服务。 Spring ORM:用于支持Hibernate等ORM工具。 Spring Web:为创建Web应用程序提供支持。 Spring Test:提供了对JUnit和TestNG测试的支持。 谈谈自己对于Spring IOC和AOP的理解 IOC(Inversion Of Controll,控制反转)是一种设计思想: 在程序中手动创建对象的控制权,交由给Spring框架来管理。IOC在其他语言中也有应用,并非Spring特有。IOC容器实际上就是一个Map(key, value),Map中存放的是各种对象。 将对象之间的相互依赖关系交给IOC容器来管理,并由IOC容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。IOC容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。在实际项目中一个Service类可能由几百甚至上千个类作为它的底层,假如我们需要实例化这个Service,可能要每次都搞清楚这个Service所有底层类的构造函数,这可能会把人逼疯。如果利用IOC的话,你只需要配置好,然后在需要的地方引用就行了,大大增加了项目的可维护性且降低了开发难度。 Spring中的bean的作用域有哪些? 1.singleton:该bean实例为单例 2.prototype:每次请求都会创建一个新的bean实例(多例)。 3.request:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。 4.session:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP session内有效。 5.global-session:全局session作用域,仅仅在基于Portlet的Web应用中才有意义,Spring5中已经没有了。Portlet是能够生成语义代码(例如HTML)片段的小型Java Web插件。它们基于Portlet容器,可以像Servlet一样处理HTTP请求。但是与Servlet不同,每个Portlet都有不同的会话。 Spring中的单例bean的线程安全问题了解吗? 概念用于理解:大部分时候我们并没有在系统中使用多线程,所以很少有人会关注这个问题。单例bean存在线程问题,主要是因为当多个线程操作同一个对象的时候,对这个对象的非静态成员变量的写操作会存在线程安全问题。 有两种常见的解决方案(用于回答的点): 1.在bean对象中尽量避免定义可变的成员变量(不太现实)。 2.在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal(线程本地化对象)中(推荐的一种方式)。 ThreadLocal解决多线程变量共享问题(参考博客):https://segmentfault.com/a/1190000009236777 Spring中Bean的生命周期: 1.Bean容器找到配置文件中Spring Bean的定义。 2.Bean容器利用Java Reflection API创建一个Bean的实例。 3.如果涉及到一些属性值,利用set方法设置一些属性值。 4.如果Bean实现了BeanNameAware接口,调用setBeanName方法,传入Bean的名字。 5.如果Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader方法,传入ClassLoader对象的实例。 6.如果Bean实现了BeanFactoryAware接口,调用setBeanClassFacotory方法,传入ClassLoader对象的实例。 7.与上面的类似,如果实现了其他*Aware接口,就调用相应的方法。 8.如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象,执postProcessBeforeInitialization方法。 9.如果Bean实现了InitializingBean接口,执行afeterPropertiesSet方法。 10.如果Bean在配置文件中的定义包含init-method属性,执行指定的方法。 11.如果有和加载这个Bean的Spring容器相关的BeanPostProcess对象,执行postProcessAfterInitialization方法。 12.当要销毁Bean的时候,如果Bean实现了DisposableBean接口,执行destroy方法。 13.当要销毁Bean的时候,如果Bean在配置文件中的定义包含destroy-method属性,执行指定的方法。 Spring框架中用到了哪些设计模式? 1.工厂设计模式:Spring使用工厂模式通过BeanFactory和ApplicationContext创建bean对象。 2.代理设计模式:Spring AOP功能的实现。 3.单例设计模式:Spring中的bean默认都是单例的。 4.模板方法模式:Spring中的jdbcTemplate、hibernateTemplate等以Template结尾的对数据库操作的类,它们就使用到了模板模式。 5.包装器设计模式:我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。 6.观察者模式:Spring事件驱动模型就是观察者模式很经典的一个应用。 7.适配器模式:Spring AOP的增强或通知(Advice)使用到了适配器模式、Spring MVC中也是用到了适配器模式适配Controller。 还有很多。。。。。。。 @Component和@Bean的区别是什么 1.作用对象不同。@Component注解作用于类,而@Bean注解作用于方法。 2.@Component注解通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中(我们可以使用@ComponentScan注解定义要扫描的路径)。@Bean注解通常是在标有该注解的方法中定义产生这个bean,告诉Spring这是某个类的实例,当我需要用它的时候还给我。 3.@Bean注解比@Component注解的自定义性更强,而且很多地方只能通过@Bean注解来注册bean。比如当引用第三方库的类需要装配到Spring容器的时候,就只能通过@Bean注解来实现。 @Configuration public class AppConfig { @Bean public TransferService transferService { return new TransferServiceImpl; } } <beans> <bean id="transferService" class="com.kk.TransferServiceImpl"/> </beans> @Bean public OneService getService(status) { case (status) { when 1: return new serviceImpl1; when 2: return new serviceImpl2; when 3: return new serviceImpl3; } } 将一个类声明为Spring的bean的注解有哪些? 声明bean的注解: @Component 组件,没有明确的角色 @Service 在业务逻辑层使用(service层) @Repository 在数据访问层使用(dao层) @Controller 在展现层使用,控制器的声明 注入bean的注解: @Autowired:由Spring提供 @Inject:由JSR-330提供 @Resource:由JSR-250提供 *扩:JSR 是 java 规范标准 Spring事务管理的方式有几种? 1.编程式事务:在代码中硬编码(不推荐使用)。 2.声明式事务:在配置文件中配置(推荐使用),分为基于XML的声明式事务和基于注解的声明式事务。 Spring事务中的隔离级别有哪几种? 在TransactionDefinition接口中定义了五个表示隔离级别的常量:ISOLATION_DEFAULT:使用后端数据库默认的隔离级别,Mysql默认采用的REPEATABLE_READ隔离级别;Oracle默认采用的READ_COMMITTED隔离级别。ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。ISOLATION_READ_COMMITTED:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生ISOLATION_REPEATABLE_READ:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。 Spring事务中有哪几种事务传播行为? 在TransactionDefinition接口中定义了八个表示事务传播行为的常量。 支持当前事务的情况:PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)。 不支持当前事务的情况:PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。 其他情况:PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于PROPAGATION_REQUIRED。 二、SpringMVC篇 什么是Spring MVC ?简单介绍下你对springMVC的理解? Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把Model,View,Controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。 Spring MVC的工作原理了解嘛? image.png Springmvc的优点: (1)可以支持各种视图技术,而不仅仅局限于JSP; (2)与Spring框架集成(如IoC容器、AOP等); (3)清晰的角色分配:前端控制器(dispatcherServlet) , 请求到处理器映射(handlerMapping), 处理器适配器(HandlerAdapter), 视图解析器(ViewResolver)。 (4) 支持各种请求资源的映射策略。 Spring MVC的主要组件? (1)前端控制器 DispatcherServlet(不需要程序员开发) 作用:接收请求、响应结果,相当于转发器,有了DispatcherServlet 就减少了其它组件之间的耦合度。 (2)处理器映射器HandlerMapping(不需要程序员开发) 作用:根据请求的URL来查找Handler (3)处理器适配器HandlerAdapter 注意:在编写Handler的时候要按照HandlerAdapter要求的规则去编写,这样适配器HandlerAdapter才可以正确的去执行Handler。 (4)处理器Handler(需要程序员开发) (5)视图解析器 ViewResolver(不需要程序员开发) 作用:进行视图的解析,根据视图逻辑名解析成真正的视图(view) (6)视图View(需要程序员开发jsp) View是一个接口, 它的实现类支持不同的视图类型(jsp,freemarker,pdf等等) springMVC和struts2的区别有哪些? (1)springmvc的入口是一个servlet即前端控制器(DispatchServlet),而struts2入口是一个filter过虑器(StrutsPrepareAndExecuteFilter)。 (2)springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。 (3)Struts采用值栈存储请求和响应的数据,通过OGNL存取数据,springmvc通过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过reques域传输到页面。Jsp视图解析器默认使用jstl。 SpringMVC怎么样设定重定向和转发的? (1)转发:在返回值前面加"forward:",譬如"forward:user.do?name=method4" (2)重定向:在返回值前面加"redirect:",譬如"redirect:http://www.baidu.com" SpringMvc怎么和AJAX相互调用的? 通过Jackson框架就可以把Java里面的对象直接转化成Js可以识别的Json对象。具体步骤如下 : (1)加入Jackson.jar (2)在配置文件中配置json的映射 (3)在接受Ajax方法里面可以直接返回Object,List等,但方法前面要加上@ResponseBody注解。 如何解决POST请求中文乱码问题,GET的又如何处理呢? (1)解决post请求乱码问题: 在web.xml中配置一个CharacterEncodingFilter过滤器,设置成utf-8; <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> (2)get请求中文参数出现乱码解决方法有两个: ①修改tomcat配置文件添加编码与工程编码一致,如下: <ConnectorURIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/> ②另外一种方法对参数进行重新编码: String userName = new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8") ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码。 Spring MVC的异常处理 ? 统一异常处理: Spring MVC处理异常有3种方式: (1)使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver; (2)实现Spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器; (3)使用@ExceptionHandler注解实现异常处理; 统一异常处理的博客:https://blog.csdn.net/ctwy291314/article/details/81983103 SpringMVC的控制器是不是单例模式,如果是,有什么问题,怎么解决? 是单例模式,所以在多线程访问的时候有线程安全问题,不要用同步,会影响性能的,解决方案是在控制器里面不能写成员变量。(此题目类似于上面Spring 中 第5题 有两种解决方案) SpringMVC常用的注解有哪些? @RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径。 @RequestBody:注解实现接收http请求的json数据,将json转换为java对象。 @ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。 SpingMvc中的控制器的注解一般用那个,有没有别的注解可以替代? 一般用@Controller注解,也可以使用@RestController,@RestController注解相当于@ResponseBody + @Controller,表示是表现层,除此之外,一般不用别的注解代替。 如果在拦截请求中,我想拦截get方式提交的方法,怎么配置? 可以在@RequestMapping注解里面加上method=RequestMethod.GET。 怎样在方法里面得到Request,或者Session? 直接在方法的形参中声明request,SpringMVC就自动把request对象传入。 如果想在拦截的方法里面得到从前台传入的参数,怎么得到? 直接在形参里面声明这个参数就可以,但必须名字和传过来的参数一样。 如果前台有很多个参数传入,并且这些参数都是一个对象的,那么怎么样快速得到这个对象? 直接在方法中声明这个对象,SpringMVC就自动会把属性赋值到这个对象里面。 SpringMVC中函数的返回值是什么? 返回值可以有很多类型,有String, ModelAndView。ModelAndView类把视图和数据都合并的一起的。 SpringMVC用什么对象从后台向前台传递数据的? 通过ModelMap对象,可以在这个对象里面调用put方法,把对象加到里面,前台就可以拿到数据。 怎么样把ModelMap里面的数据放入Session里面? 可以在类上面加上@SessionAttributes注解,里面包含的字符串就是要放入session里面的key。 SpringMvc里面拦截器是怎么写的: 有两种写法,一种是实现HandlerInterceptor接口,另外一种是继承适配器类,接着在接口方法当中,实现处理逻辑;然后在SpringMvc的配置文件中配置拦截器即可: <!-- 配置SpringMvc的拦截器 --> <mvc:interceptors> <!-- 配置一个拦截器的Bean就可以了 默认是对所有请求都拦截 --> <bean id="myInterceptor" class="com.zwp.action.MyHandlerInterceptor"></bean> <!-- 只针对部分请求拦截 --> <mvc:interceptor> <mvc:mapping path="/modelMap.do" /> <bean class="com.zwp.action.MyHandlerInterceptorAdapter" /> </mvc:interceptor> </mvc:interceptors> 注解原理: 注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。我们通过反射获取注解时,返回的是Java运行时生成的动态代理对象。通过代理对象调用自定义注解的方法,会最终调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值。而memberValues的来源是Java常量池 三、Mybatis篇 什么是MyBatis? MyBatis是一个可以自定义SQL、存储过程和高级映射的持久层框架。 讲下MyBatis的缓存 MyBatis的缓存分为一级缓存和二级缓存,一级缓存放在session里面,默认就有, 二级缓存放在它的命名空间里,默认是不打开的,使用二级缓存属性类需要实现Serializable序列化接口, 可在它的映射文件中配置<cache/> Mybatis是如何进行分页的?分页插件的原理是什么? 1)Mybatis使用RowBounds对象进行分页,也可以直接编写sql实现分页,也可以使用Mybatis的分页插件。 2)分页插件的原理:实现Mybatis提供的接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql。 举例:select * from student,拦截sql后重写为:select t.* from (select * from student)t limit 0,10 简述Mybatis的插件运行原理,以及如何编写一个插件? 1)Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、 Executor这4种接口的插件,Mybatis通过动态代理, 为需要拦截的接口生成代理对象以实现接口方法拦截功能, 每当执行这4种接口对象的方法时,就会进入拦截方法, 具体就是InvocationHandler的invoke方法,当然, 只会拦截那些你指定需要拦截的方法。 2)实现Mybatis的Interceptor接口并复写intercept方法, 然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可, 记住,别忘了在配置文件中配置你编写的插件。 Mybatis动态sql是做什么的?都有哪些动态sql?能简述一下动态sql的执行原理不? 1)Mybatis动态sql可以让我们在Xml映射文件内, 以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能。 2)Mybatis提供了9种动态sql标签:trim|where|set|foreach|if|choose|when|otherwise|bind。 3)其执行原理为,使用OGNL从sql参数对象中计算表达式的值, 根据表达式的值动态拼接sql,以此来完成动态sql的功能。 #{}和${}的区别是什么? 1)#{}是预编译处理,${}是字符串替换。 2)Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值(有效的防止SQL注入); 3)Mybatis在处理${}时,就是把${}替换成变量的值。 为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里? Hibernate属于全自动ORM映射工具, 使用Hibernate查询关联对象或者关联集合对象时, 可以根据对象关系模型直接获取,所以它是全自动的。 而Mybatis在查询关联对象或关联集合对象时, 需要手动编写sql来完成,所以,称之为半自动ORM映射工具。 Mybatis是否支持延迟加载?如果支持,它的实现原理是什么? 1)Mybatis仅支持association关联对象和collection关联集合对象的延迟加载, association指的就是一对一,collection指的就是一对多查询。 在Mybatis配置文件中, 可以配置是否启用延迟加载lazyLoadingEnabled=true|false。 2)它的原理是,使用CGLIB创建目标对象的代理对象, 当调用目标方法时,进入拦截器方法, 比如调用a.getB.getName, 拦截器invoke方法发现a.getB是null值, 那么就会单独发送事先保存好的查询关联B对象的sql, 把B查询上来,然后调用a.setB(b), 于是a的对象b属性就有值了, 接着完成a.getB.getName方法的调用。 这就是延迟加载的基本原理。 MyBatis与Hibernate有哪些不同? 1)Mybatis和hibernate不同,它不完全是一个ORM框架, 因为MyBatis需要程序员自己编写Sql语句, 不过mybatis可以通过XML或注解方式灵活配置要运行的sql语句, 并将java对象和sql语句映射生成最终执行的sql, 最后将sql执行的结果再映射生成java对象。 2)Mybatis学习门槛低,简单易学,程序员直接编写原生态sql, 可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发, 例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁, 一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性, 如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。 3)Hibernate对象/关系映射能力强,数据库无关性好, 对于关系模型要求高的软件(例如需求固定的定制化软件) 如果用hibernate开发可以节省很多代码,提高效率。 但是Hibernate的缺点是学习门槛高,要精通门槛更高, 而且怎么设计O/R映射,在性能和对象模型之间如何权衡, 以及怎样用好Hibernate需要具有很强的经验和能力才行。 总之,按照用户的需求在有限的资源环境下只要能做出维护性、 扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。 MyBatis的好处是什么? 1)MyBatis把sql语句从Java源程序中独立出来,放在单独的XML文件中编写, 给程序的维护带来了很大便利。 2)MyBatis封装了底层JDBC API的调用细节,并能自动将结果集转换成Java Bean对象, 大大简化了Java数据库编程的重复工作。 3)因为MyBatis需要程序员自己去编写sql语句, 程序员可以结合数据库自身的特点灵活控制sql语句, 因此能够实现比Hibernate等全自动orm框架更高的查询效率,能够完成复杂查询。 简述Mybatis的Xml映射文件和Mybatis内部数据结构之间的映射关系? Mybatis将所有Xml配置信息都封装到All-In-One重量级对象Configuration内部。 在Xml映射文件中,<parameterMap>标签会被解析为ParameterMap对象, 其每个子元素会被解析为ParameterMapping对象。 <resultMap>标签会被解析为ResultMap对象, 其每个子元素会被解析为ResultMapping对象。 每一个<select>、<insert>、<update>、<delete> 标签均会被解析为MappedStatement对象, 标签内的sql会被解析为BoundSql对象。 什么是MyBatis的接口绑定,有什么好处? 接口映射就是在MyBatis中任意定义接口,然后把接口里面的方法和SQL语句绑定, 我们直接调用接口方法就可以,这样比起原来了SqlSession提供的方法我们可以有更加灵活的选择和设置. 接口绑定有几种实现方式,分别是怎么实现的? 接口绑定有两种实现方式,一种是通过注解绑定,就是在接口的方法上面加 上@Select@Update等注解里面包含Sql语句来绑定, 另外一种就是通过xml里面写SQL来绑定,在这种情况下, 要指定xml映射文件里面的namespace必须为接口的全路径名. 什么情况下用注解绑定,什么情况下用xml绑定? 当Sql语句比较简单时候,用注解绑定;当SQL语句比较复杂时候,用xml绑定,一般用xml绑定的比较多 MyBatis实现一对一有几种方式?具体怎么操作的? 有联合查询和嵌套查询,联合查询是几个表联合查询,只查询一次, 通过在resultMap里面配置association节点配置一对一的类就可以完成; 嵌套查询是先查一个表,根据这个表里面的结果的外键id, 去再另外一个表里面查询数据,也是通过association配置, 但另外一个表的查询通过select属性配置。 Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别? 能,Mybatis不仅可以执行一对一、一对多的关联查询, 还可以执行多对一,多对多的关联查询,多对一查询, 其实就是一对一查询,只需要把selectOne修改为selectList即可; 多对多查询,其实就是一对多查询,只需要把selectOne修改为selectList即可。 关联对象查询,有两种实现方式,一种是单独发送一个sql去查询关联对象, 赋给主对象,然后返回主对象。另一种是使用嵌套查询,嵌套查询的含义为使用join查询, 一部分列是A对象的属性值,另外一部分列是关联对象B的属性值, 好处是只发一个sql查询,就可以把主对象和其关联对象查出来。 MyBatis里面的动态Sql是怎么设定的?用什么语法? MyBatis里面的动态Sql一般是通过if节点来实现,通过OGNL语法来实现, 但是如果要写的完整,必须配合where,trim节点,where节点是判断包含节点有 内容就插入where,否则不插入,trim节点是用来判断如果动态语句是以and 或or 开始,那么会自动把这个and或者or取掉。 Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式? 第一种是使用<resultMap>标签,逐一定义列名和对象属性名之间的映射关系。 第二种是使用sql列的别名功能,将列别名书写为对象属性名, 比如T_NAME AS NAME,对象属性名一般是name,小写, 但是列名不区分大小写,Mybatis会忽略列名大小写,
-
第 2 课 Python Web 企业门户 - 框架构建