环境准备
1、 创建一个Django后,Django的目录:
│ manage.py
│
├─Django_s1
│ settings.py
│ urls.py
│ wsgi.py
│ __init__.py
│
│ templates
创建app,通过命令:
python manage.py startapp app01
创建app之后的目录结构如下:
│ manage.py
│
├─app01
│ │ admin.py
│ │ apps.py
│ │ models.py
│ │ tests.py
│ │ views.py
│ │ __init__.py
│ │
│ └─migrations
│ __init__.py
│
├─Django_s1
│ │ settings.py
│ │ urls.py
│ │ wsgi.py
│ │ __init__.py
│ │
│
└─templates
2、 创建一个项目之后首先需要做的配置
Django_s1目录下settings.py文件中需要做如下配置:
- 找到MIDDLEWARE部分,将第四行内容注释掉:
'django.middleware.csrf.CsrfViewMiddleware',
- 找到TEMPLATES部分,如果没有如下代码,则需要添加:
'DIRS': [os.path.join(BASE_DIR, 'templates')]
- 文件的最后添加静态文件目录,需要注意的是这里是一个元组没所以后面的逗号必须添加
STATICFILES_DIRS=(
os.path.join(BASE_DIR,"static"),
)
同时需要创建一个名字为static的文件夹,用于存放静态文件
3、 到此为止基本的配置就已经完成,最后的目录结构如下:
│ manage.py
│
├─app01
│ │ admin.py
│ │ apps.py
│ │ models.py
│ │ tests.py
│ │ views.py
│ │ __init__.py
│ │
│ └─migrations
│ __init__.py
│
├─Django_s1
│ │ settings.py
│ │ urls.py
│ │ wsgi.py
│ │ __init__.py
│
│
├─static
└─templates
4、 创建一个测试页面,验证:
- 主要的业务代码是放在app01目录下view.py文件中,先在view.py中写如下测试代码:
from django.shortcuts import HttpResponse
def index(request):
return HttpResponse("index")
- 同时在url.py中添加上对应关系:
from app01 import views urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/', views.index),
]
登录http://127.0.0.1:8000/index/
5、 写一个简单的登录页面
这里我们需要记住:
templates目录中放的是html文件
static中放的是静态文件即css,以及js文件
views.py中写业务代码
urls.py中写路由关系
首先在templates里写login.html,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login/" method="post">
<p>
<input type="text" name="user" placeholder="用户名">
</p>
<p>
<input type="password" name="pwd" placeholder="密码">
</p>
<input type="submit" value="提交">
</form>
</body>
</html>
在views,添加如下代码:
def login(request):
if request.method=="GET":
return render(request,"login.html")
elif request.method == "POST":
u = request.POST.get("user")
p = request.POST.get("pwd")
if u == "zhaofan" and p == "":
return redirect('/index/')
else:
return render(request,"login.html")
else:
return redirect('/index/')
在urls路由关系里添加如下代码,黄色背景部分:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/', views.index),
url(r'^login/', views.login),
]
这样通过浏览器访问效果如下:
关于获取数据和文件上传
实现的代码如下:
1、 在views.py里写如下函数
def login(request):
if request.method=="GET":
return render(request,"login.html")
elif request.method == "POST":
# v = request.POST.get("gender")
# print(v)
# f = request.POST.getlist("city")
# print(f)
# file = request.POST.get("upload")
# print(file)
obj = request.FILES.get("upload")
print(obj,type(obj),obj.name)
import os
file_path = os.path.join("upload_dir",obj.name)
f = open(file_path,mode="wb")
for i in obj.chunks():
f.write(i)
f.close()
return render(request, "login.html")
else:
return redirect('/index/')
2、 login.html文件中代码如下;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login/" method="post" enctype="multipart/form-data">
<p>
<input type="text" name="user" placeholder="用户名">
</p>
<p>
<input type="password" name="pwd" placeholder="密码">
</p>
<p>
男:<input type="radio" name="gender" value="1">
女:<input type="radio" name="gender" value="2">
</p>
<p>
乒乓球:<input type="checkbox" name = "favor" value="1">
篮球:<input type="checkbox" name = "favor" value="2">
羽毛球:<input type="checkbox" name = "favor" value="3">
</p>
<p>
<select name="city" multiple>
<option value="sh">上海</option>
<option value="bj">北京</option>
<option value="tj">天津</option>
</select>
</p>
<p>
<input type="file" name="upload">
</p>
<input type="submit" value="提交">
</form>
</body>
</html>
3、 关于上述代码中知识点的总结:
- 当获取单个值的时候类似单选框,可以给标签设置name属性,然后通过类似request.POST.get("gender")方式获取相应的值即:
request.POST.get("标签name属性值")
- 当获取多个值的时候类似复选框以及可以多选的select的时候,通过request.POST.getlist("city")的方式获取相应的内容,这样得到的是一个列表,即:
request.POST.getlist("标签name属性值")
- 当时获取上传文件的时候
首先form表单中应该有如下属性:enctype="multipart/form-data"
然后在views.py中通过obj = request.FILES.get("upload")获取文件的一个对象,通过打印可以看出这个对象的详细内容为:<class 'django.core.files.uploadedfile.InMemoryUploadedFile'>即:
request.FILES.get("标签name属性值")
最后通过如下方式循环将文件接收:
import os
file_path = os.path.join("upload_dir",obj.name)
f = open(file_path,mode="wb")
for i in obj.chunks():
f.write(i)
f.close()
这样最后所有的上传文件都会放在upload_dir目录下,当然这个目录需要自己提前创建
关于FBV和CBV
1、 FBV
FBV对应的是function base view
urls.py
index--->函数名
views.py
def 函数(request)
2、 CBV
CBV对应的是class base view
3、 之前写的都是FBV的方式多点,下面通过一个CBV的例子来理解CBV
- 首先先写一个home.html文件,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/home/" method="post">
<input type="text" name="user">
<input type="submit">
</form>
</body>
</html>
- views.py中写如下代码:
from django.views import View
# 这里Home需要继承View
class Home(View):
def get(self,request):
print(request.method)
return render(request,"home.html")
def post(self,request):
print(request.method)
return render(request, "home.html")
- urls.py中写如下代码高亮部分:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/', views.index),
url(r'^login/', views.login),
url(r'^home/', views.Home.as_view()), ]
- 效果如下
当访问页面内容时:
查看django打印的日志可以看出都是的get请求:
当点击提交的时候:查看django的日志可以看出是post请求;
4、 关于CBV,django在内部是如何实现的?
分析:
当访问页面的时候:头部中请求的方法是GET方式:
当点击提交的时候:头部中的请求的方法是POST方式:
其实当发送请求的时候,是将Request URL以及Request Method同时传递给django,先匹配url,然后去找对应的类,然后找相应的方法,也就是post或者get等,这里判断是post还是get是通过反射实现的。
查看view类里面有一个函数:dispatch函数
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
从函数可以看出是dispatch先做了一个反射的功能
所以这个请求的过程是:请求--->dispatch--->get/post
将views.py中的代码更改为如下:
from django.views import View
# 这里Home需要继承View
class Home(View):
# 这样这里就相当于一个装饰器的功能,可以自己定制化内容
def dispatch(self, request, *args, **kwargs):
# 调用父类中dispatch方法
print("before")
result = super(Home, self).dispatch(request,*args,**kwargs)
print("after")
return result
def get(self,request):
print(request.method)
return render(request,"home.html")
def post(self,request):
print(request.method)
return render(request, "home.html")
这样从效果就可以看出当再次访问home页面的时候,每次都需要打印before以及after
5、 模板语言中字典的循环
views.py中写如下代码:
USER_DICT = {
"k1":"root1",
"k2":"root2",
"k3":"root3",
"k4":"root4",
"k5":"root5",
} def index(request):
return render(request,"index.html",{"user_dict":USER_DICT})
创建一个index.html文件,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul>
{% for k,row in user_dict.items %}
<li>{{ k }}-{{ row }}</li>
{% endfor %}
</ul>
</body>
</html>
按照上面的循环方式结果如下:
同样的字典循环包含以下几种方式:
user_dict.items ---- 这样循环row为(k,value)
user_dict.values ---- 这样循环row为value值
user_dict ----这样循环的话row为k值
关于URL路由系统
1、 实现一个点击查看详情的例子(方法一)
views.py中的代码如下;
USER_DICT = {
"k1":{"name":"root1","email":"root1@qq.com"},
"k2":{"name":"root2","email":"root2@qq.com"},
"k3":{"name":"root3","email":"root3@qq.com"},
"k4":{"name":"root4","email":"root4@qq.com"}, } def index(request):
return render(request,"index.html",{"user_dict":USER_DICT}) def detail(request):
nid = request.GET.get("nid")
detail_info = USER_DICT[nid]
return render(request,"detail.html",{"detail_info":detail_info})
index.html文件中的代码如下;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul>
{% for k,row in user_dict.items %}
<li><a target="_blank" href="/detail/?nid={{ k }}">{{ row.name }}</a></li>
{% endfor %}
</ul>
</body>
</html>
detail.html代码为如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>详细信息</h1>
<h6>用户名:{{ detail_info.name }}</h6>
<h6>邮箱:{{ detail_info.email }}</h6>
</body>
</html>
urls.py中写如下代码高亮部分:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/', views.index),
url(r'^login/', views.login),
url(r'^home/', views.Home.as_view()),
url(r'^detail/', views.detail), ]
实现效果为当打开index主页的时候显示:
点击某个选项,则可以显示详细信息
2、 实现一个点击查看详情的例子(方法二)
urls.py中的代码如下高亮部分;
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/', views.index),
url(r'^login/', views.login),
url(r'^home/', views.Home.as_view()),
#url(r'^detail/', views.detail),
url(r'^detail-(\d+).html', views.detail), ]
views.py中的代码如下:
USER_DICT = {
"":{"name":"root1","email":"root1@qq.com"},
"":{"name":"root2","email":"root2@qq.com"},
"":{"name":"root3","email":"root3@qq.com"},
"":{"name":"root4","email":"root4@qq.com"}, } def index(request):
return render(request,"index.html",{"user_dict":USER_DICT})
def detail(request,nid):
# return HttpResponse(nid)
detail_info = USER_DICT[nid]
return render(request,"detail.html",{"detail_info":detail_info})
index.html中的代码为:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul>
{% for k,row in user_dict.items %}
<li><a target="_blank" href="/detail-{{ k }}.html">{{ row.name }}</a></li>
{% endfor %}
</ul>
</body>
</html>
detail.html中代码不变
最终的效果,点击详细页面之后,地址变为/detail-2.html而不是之前的/detail?nid-2.html:
3、 针对上述的例子,我们将urls.py进行修改:
将url(r'^detail-(\d+).html', views.detail),修改为:
url(r'^detail-(\d+)-(\d+).html', views.detail),
这样就存在两个正则,这样在views.py中获取到的时候也需要两个参数,def detail(request,nid,uid),并且这两个参数和顺序有关,第一个参数就是匹配的第一个正则,第二个匹配第二个正则,这样就会有个弊端,一旦调用函数的时候参数传递错误,那个真个函数里设计这两个参数的计算都会出现问题。
所以我们通常用如下方法:
url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html', views.detail),
这样就相当于分组,这样就不会应该顺序问题而影响结果
其实在views.py中有一个终极的方法:
def detail(*args,**kwargs),这样当多个参数的就会传递到*args里,当传递字典类型的参数的时候就会传递到**kwargs
4、 name
name是对URL路由关系进行命名,以后可以根据此名称生成自己想要的URL
- url(r'^sdfffddddd/', views.index,name="i1"),
- url(r'^sdfffddddd/(\d+)/(\d+)/', views.index,name="i2"),
- url(r'^sdfffddddd/(?P<nid>\d+)/(?P<uid>\d+)/', views.index,name="i3"),
注意:
获取当前URL
request.path_info
如果def func(request,*args,**kwargs)
from django.urls impore reverse
url1 = reverse("i1") ----这样就会生成/sdfffddddd/
url2 = reverse("i2",args=(1,2,)) ---生成/1/2/
url3 = reverse("i3",kwargs={"pid":1, "uid":9}) ---生成/1/9
在模板语言中:
{% url "i1" %} ---生成/sdfffddddd/
{% url "i2" 1 2 %} --生成/1/2/
{% url "i3" pid=1 uid=3 %} ---生成/1/3/
5、 路由分发
当有 多个app的时候
当请求来的时候先到项目的urls.py里,这里的配置如下:
from django.conf.urls import url,include
from django.contrib import admin urlpatterns = [
url(r'^app01/',include("app01.urls")),
url(r'^app02/',include("app02.urls")), ]
根据不同的app去不同的app下找相应的app级别的urls
这样就实现了路由的分发
Django的ORM
1、 创建类
根据类自动创建数据库表
创建类的位置是在你创建的app目录下有一个models.py,就在这个文件中创建类,写一个简单的类的例子:
class UserInfo(models.Model):
#django会默认创建一个id列,并且是自增,主键 #创建用户名列,字符类型,指定长度
username = models.CharField(max_length=32)
#c创建密码列,字符类型,指定长度
password = models.CharField(max_length=64)
创建过之后执行:
python manage.py makemigrations
执行这个命令之后,Django会去找models.py文件
因为我们是在app01下的models.py,所以需要在settings.py中进行指定,找到:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
在最后添加"app01",
这样当执行python manage.py makemigrations,就会找到app01下的models.py从而在app01目录下的migrations目录下生成对应的文件,这个文件就是用于创建数据库表用的,执行过程如下:
D:\python培训\Django_s1>python manage.py makemigrations
Migrations for 'app01':
app01\migrations\0001_initial.py:
- Create model UserInfo D:\python培训\Django_s1>
然后执行python manage.py migrate,这样就会在数据库中创建表结构,执行过程如下:
D:\python培训\Django_s1>python manage.py migrate
Operations to perform:
Apply all migrations: admin, app01, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying app01.0001_initial... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying sessions.0001_initial... OK D:\python培训\Django_s1>
因为Django默认使用的是sqlite数据库库,所以这个时候会在项目目录下生成一个db.sqlite3的文件,如果想要查看需要第三方程序查看,如果想要用mysql数据库,则需要更改配置。
更改配置如下:
找打settings.py中的如下内容,并注释:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
添加如下内容:并配置自己的数据库信息
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':'dbname',
'USER': 'root',
'PASSWORD': 'xxx',
'HOST': '',
'PORT': '',
}
}
由于Django内部连接mysql用的是MySQLdb模块,而python3中已经没有了这个模块,所以需要使用pymysql来代替MySQLdb,配置如下:
在与项目同名的文件目录下的__init__.py文件中添加如下内容:
import pymysql
pymysql.install_as_MySQLdb()
这样重新执行python manage.py migrate即可
查看数据你会看到如下表:
其中只有一个表app01_userinfo是你自己通过类创建的其他都是django自己创建的,查看app01_userinfo表结构信息:
2、 添加数据
方法一:(推荐这种方法)
models.UserInfo.objects.create(username = "root", password = "123",)
首先在app01下的urls.py中添加如下内容:
url(r'^app02/',include("app02.urls")),
然后在views.py中添加如下内容:
from app01 import models
def orm(request):
models.UserInfo.objects.create(
username = "root",
password = "",
)
return HttpResponse("orm is ok")
然后通过浏览器访问http://127.0.0.1:8000/app01/orm/
这样就在数据库里添加了一条数据数据
方法二:
- obj = models.UserInfo(username="dean",password = "123456")
obj.save()
然后通过浏览器访问http://127.0.0.1:8000/app01/orm/
这样就在数据库里添加了一条数据数据
方法三:
dic={"username":"erric","password":"555"}、models.UserInfo.objects.create(**dic)
return HttpResponse("orm is ok")
然后通过浏览器访问http://127.0.0.1:8000/app01/orm/
这样就在数据库里添加了一条数据数据
3、 查询数据
查询所有数据
result = models.UserInfo.objects.all()
这样得到的result通过打印时如下:
<QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>
这个QuerySet是Django创建的一种类似列表的格式,这里面每个元素就是数据库每行的一个对象,这样我们就能通过循环获取每行的数据,方法如下:
result = models.UserInfo.objects.all()
print(result)
for row_obj in result:
print(row_obj.id,row_obj.username,row_obj.password)
return HttpResponse("orm is ok")
根据条件 查询数据
result =models.UserInfo.objects.filter(username="root")
这里的filter就相当于sql语句中的where条件
4、 删除数据
models.UserInfo.objects.delete() 删除所有数据
models.UserInfo.objects.filter(id=2).delete() 通过条件删除
5、 更新数据
models.UserInfo.objects.all().update(password=222)
上面是将所有的的密码都更改,
如果想要根据条件更改则可以:
models.UserInfo.objects.filter(id=2).update(password=888)
继续Django的更多相关文章
-
异步任务队列Celery在Django中的使用
前段时间在Django Web平台开发中,碰到一些请求执行的任务时间较长(几分钟),为了加快用户的响应时间,因此决定采用异步任务的方式在后台执行这些任务.在同事的指引下接触了Celery这个异步任务队 ...
-
《Django By Example》第四章 中文 翻译 (个人学习,渣翻)
书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:祝大家新年快乐,这次带来<D ...
-
django server之间通过remote user 相互调用
首先,场景是这样的:存在两个django web应用,并且两个应用存在一定的联系.某些情况下彼此需要获取对方的数据. 但是我们的应用肯经都会有对应的鉴权机制.不会让人家随随便便就访问的对吧.好比上车要 ...
-
Mysql事务探索及其在Django中的实践(二)
继上一篇<Mysql事务探索及其在Django中的实践(一)>交代完问题的背景和Mysql事务基础后,这一篇主要想介绍一下事务在Django中的使用以及实际应用给我们带来的效率提升. 首先 ...
-
Mysql事务探索及其在Django中的实践(一)
前言 很早就有想开始写博客的想法,一方面是对自己近期所学知识的一些总结.沉淀,方便以后对过去的知识进行梳理.追溯,一方面也希望能通过博客来认识更多相同技术圈的朋友.所幸近期通过了博客园的申请,那么今天 ...
-
《Django By Example》第三章 中文 翻译 (个人学习,渣翻)
书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:第三章滚烫出炉,大家请不要吐槽文中 ...
-
《Django By Example》第二章 中文 翻译 (个人学习,渣翻)
书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:翻译完第一章后,发现翻译第二章的速 ...
-
《Django By Example》第一章 中文 翻译 (个人学习,渣翻)
书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:本人目前在杭州某家互联网公司工作, ...
-
Django
一.Django 简介 Django 是一个由 Python 写成的开放源代码的 Web 应用框架.它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是 CMS(内容管理系统) ...
-
Django admin定制化,User字段扩展[原创]
前言 参考上篇博文,我们利用了OneToOneField的方式使用了django自带的user,http://www.cnblogs.com/caseast/p/5909248.html , 但这么用 ...
随机推荐
-
使用NUnit为游戏项目编写高质量单元测试的思考
0x00 单元测试Pro & Con 最近尝试在我参与的游戏项目中引入TDD(测试驱动开发)的开发模式,因此单元测试便变得十分必要.这篇博客就来聊一聊这段时间的感悟和想法.由于游戏开发和传统软 ...
-
ASP.NET MVC中利用AuthorizeAttribute实现访问身份是否合法以及Cookie过期问题的处理
话说来到上海已经快半年了,时光如白驹过隙,稍微不注意,时间就溜走了,倒是没有那么忙碌,闲暇之际来博客园还是比较多的,记得上次在逛博问的时候看到有同志在问MVC中Cookie过期后如何作相关处理,他在阐 ...
-
使用node-webkit开发exe窗口程序
首发:个人博客,更新&纠错&回复 ====关于原生程序与壳中程序的议论begin==== 在所有用户windows机器上都能直接跑的程序,如果不采用微软系的语言,如VB,C++,C#等 ...
-
CoffeeScript学习(1)——Quick Start
什么是CoffeeScript CoffeeScript 是一门编译到 JavaScript 的小巧语言. 在 Java 般笨拙的外表下, JavaScript 其实有着一颗华丽的心脏. Coffee ...
-
ST表poj3264
/* ST表多次查询区间最小值 设 g[j][i] 表示从第 i 个数到第 i + 2 ^ j - 1 个数之间的最小值 类似DP的说 ans[i][j]=min (ans[i][mid],ans ...
-
java----代码打包
打包 文件生成在out目录下 D:\IDEA代码\out\artifacts\IDEA_jar 注意打包好像只能打包src下面的代码 不在src目录下的一些文件,自己文件添加到打包好的目录下 可以选择 ...
-
洛谷P3980 志愿者招募
题意:懒得写了...... 解: 一开始想的是每天建点,每种人建点,然后连边费用流,发现一个人可以管辖多天,不好处理. 回想起了网络流24题中的"最长k可重线段集","最 ...
-
python 全栈开发,Day104(DRF用户认证,结算中心,django-redis)
考试第二部分:MySQL数据库 6. MySQL中char和varchar的区别(1分) char是定长,varchar是变长. char的查询速度比varchar要快. 7. MySQL中va ...
-
UNIX环境编程学习笔记(25)——信号处理进阶学习之 sigaction 函数
lienhua342014-11-05 sigaction 函数跟 signal 函数一样,用于设置信号处理函数.此函数是用于取代 UNIX 早期版本使用的 signal 函数.UNIX 早期版本的 ...
-
SpringMVC中的参数绑定总结
众所周知,springmvc是用来处理页面的一些请求,然后将数据再通过视图返回给用户的,前面的几篇博文中使用的都是静态数据,为了能快速入门springmvc,在这一篇博文中,我将总结一下springm ...