Django-开放静态资源-获取请求携带的数据-pychram连接数据库-修改Django默认数据库-DjangoORM操作--表管理-记录管理-01
目录
django项目就类似于一所大学,各个app 就相当于二级学院
以登录功能为例走一个django项目(今日内容 引子)
关于静态资源访问
你可能会发现,在我们目前的 django 项目中的 html 模板中链入的 css 、js (这里只服务器本地的,CDN等除外)明明路径是对的,请求得到的却是 404 资源不存在
为什么要配置静态文件才能获取静态资源
用户可以访问的资源,都在 url 中
只有 url 中开设(配置)相关的资源你才能访问到(不然就可以根据路径把网站源码都拿过去了)
后端资源一般都需要手动指定是否需要暴露给用户
配置完之后也只有输入完整的文件路径才能访问到(也相对是一种保护措施)
对于前端已经写好了的文件,我们只是拿过来使用,那么这些文件都可以称之为 “静态文件”
html文件默认全部放在 templates 文件夹下(并且,如果是命令行创建的项目,并不会自带 templates 文件夹,自己创建的就需要去配置文件里配置)
常见的静态文件种类
css
js
iamge (图片)
bootstrap、fontawesome等前端框架,已经写好了的
bootstrap-3.3.7-dist,bootstrap 是依赖于 jquery的,所以在导bootstrap 之前要先导入 jquery
如何配置来开启访问权限
默认的 django 项目 是没有 static 这个文件的,需要自己手动创建 static 文件夹,然后需要去 settings.py 文件配置 static 静态资源相关
# ... 差不多在 settings.py 文件的最下面
STATIC_URL = '/static/' # 接口前缀(跟请求路径相关)
# 只要你想访问静态文件中的资源,路径就必须以 /static/ 开头
# STATIC_URL = '/xxx/' # 引用静态文件资源的地方要改成 /xxx/....
# 下面这个是要手动配置的,手动将所有的静态资源文件暴露给用户
STATICFILES_DIRS = [ # 跟实际文件的查找位置相关
# 这里可以配置很多个,就类似于操作系统环境变量的查找,依次去文件夹里找
os.path.join(BASE_DIR, "static"), # 真正的文件夹路径
]
创建完 static文件夹后,一般还会再在里面手动创建三个文件夹
- css 放当前网站所有的 样式 文件(自己写的)
- js 放当前网站所有的 js 文件(自己写的)
- image 放当前网站所有的 图片 文件
禁用浏览器缓存
写 django 项目最好禁用掉浏览器缓存,不然可能写的代码页面上缓存看不到效果、变化(资源加载地址等等)


要开着 F12开发者工具查看 *****

django的自动重启机制(热启动)
实时监测文件代码变化,只要有变化,就会自动重启,可能代码还没有写完就会自动报错(如果有语法错误可能不会自动重启,遇到逻辑错误就会重启)
静态文件接口动态解析
如果你的产品经理要让你上1000个静态资源的前缀改了,再改回来,总之就是改来改去,怎么办?
备注:这个一般是结合 static 静态文件配置来用的
使用静态文件接口动态解析
...html代码(这一块一般在 head 标签里引用)
{% load static %} <-- 开启静态文件接口动态解析 -->
<link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
...html代码
向服务器发送数据
利用 form 表单默认的 get 请求携带
form 表单提交方式默认是 get 请求,携带数据的方式是 url 问号后面跟数据(浏览器地址栏直接拼接也是一样的,本质都是发送一个请求过去,数据都封装成了请求的数据格式)
?username=jason&password=123
form 表单改用 post 请求提交数据
- 把html模版中 form 表单的 method 改成 post(method=‘post’)
- 去 settings.py 里 把 CSRF 这个中间件禁用掉

回顾:action提交地址的三种写法
- 不写的情况下 默认往当前地址提交(url)
- 还可以写后缀/index/ (django项目常用这种)
- 还可以写全路径
代码区分请求方式
request.method 能够获取前端请求方式(并且是全大写的字符串 POST、GET)
def test_request_way(request):
print(request.method, type(request.method))
# GET <class 'str'> # 直接浏览器敲 http://127.0.0.1:8000/test_request_way/ 的方绘制
return HttpResponse('alallala')
推荐写法
可以根据这个来判断请求方式,对于不同的请求方式作出不同的处理
def del_user(request):
if request. method == 'POST':
# post 请求的逻辑处理
return HttpResponse('这是一个 POST 请求!')
# get 请求的逻辑处理(如果是 post,上面就已经return 了,不会执行到这里)
return HttpResponse('这是一个 GET 请求!')
获取请求带过来的数据
WSGI帮忙封装了 request 等,也经过了 Django后端,才有了request 这个对象(请求相关内容 全在 environ 里面)

GET、POST
request.POST
获取前端表单 POST 提交的所有数据(就类似于一个大字典)
取数据
request.POST.get('username') # 虽然value是一一个列表但是默认只取列表最后一个元素
password = request.POST['password'] # --->强烈不建议你使用中括号的形式取值,不存在会直接报错
# 如果想直接把列表全部拿出来 --> request.POST.getlist('hobby') # 获取用户爱好、下拉框的选项

request.GET
获取前端 GET 提交的所有数据(就类似于一个大字典)
取数据
request.GET.get('username') # 虽然value是一一个列表但是默认只取列表最后一个元素
# 如果没有 get 请求携带的数据,就是一个空字典
password = request.GET['password'] # --->强烈不建议你使用中括号的形式取值,不存在会直接报错
# 如果想直接把列表全部拿出来 --> request.GET.getlist('hobby') # 获取用户爱好、下拉框的选项
pycharm 图形化工具连接数据库

准备工作,安装插件
然后安装一下插件( downloads...)

配置连接信息
一定要注意选择那个 MySQL for 5.1(mysql 版本不高的时候),就两个选项反正不行换一个试试嘛
不然 Test Connection 可能会报错

图形页面基本操作
不是重点,鼠标悬浮上去都有提示,自己看吧。。。
过滤多余的字符编码之类的?

不显示数据表?

修改 django 项目配置(应用mysql)
django 默认使用的是自带的 sqlite 数据库(一种小型的做测试用的数据库)
要让 django 项目应用其他数据库(mysql),需要做如下两步配置
在 settings.py 里面配置数据库连接信息
配置的时候 key 必须全大写
... 省略一堆 配置信息
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 直接把原来的 sqlite3 改成 mysql
# mysql 相关配置信息
'HOST': '127.0.0.1',
'PORT': 3306,
'USER': 'root',
'PASSWORD': '000000',
'NAME': 'day51', # 数据库名
'CHARSET': 'utf8'
}
}
... 其他配置信息
指定数据库“软件”?
在项目名下的 __init__.py 文件或者是应用名文件下的 __init__.py 文件下加入一段代码(指定使用的数据库软件?)
django 默认用 MySQLdb 连数据库的(需要自己引入,MySQLdb 比较老了,兼容性也不太好,所以要自己指定)
import pymysql
pymysql.install_as_MySQLdb() # 把 pymysql 装成 MySQLdb 或者 取别名成 MySQLdb ?
django ORM
跟之前 手撸ORM 核心思路一样,只不过这个更加强大而已(强大不知道多少倍去了)
关系映射:
表 ---> 类
一条条记录 ---> 对象
字段对应的值 ---> 对象的属性
在models.py 里创表模型类
django 会默认给你的表创建一个名为 id 的主键字段,所以可以不写这个 id 主键
但如果不是名为 id (是 s_id) 那还是得自己写,一旦你已经指定了主键字段 那么 django 就不会主动再给你创建了
注意点
- CharField 必须指定 max_length 参数,不指定会报错
- 字段修改的注意点(下面有展开介绍)
- 其他注意点 ...
app01/models.py
from django.db import models
# Create your models here.
class User(models.Model):
# 将id字段设置为User表主键字段 在django orm中 你可以不写主键字典 django会默认给你的表创建一个名为id的主键字段
# id = models.AutoField(primary_key=True) # 一旦你自己指定了主键字段 那么django就不会自动再帮你创建了
username = models.CharField(max_length=32) # username varchar(32) CharField必须要指定max_length参数
# password = models.IntegerField() # password int
password = models.CharField(max_length=64)
# addr = models.CharField(max_length=32,default='China') # default该字段默认值
# age = models.IntegerField(null=True) # 该字段允许为空
def __str__(self): # 重写了对象的 __str__ 方法,这样后面打印对象的时候就是这个字符串了
return '我是user表中的对象:%s' % self.username
创建表、修改表--数据库迁移命令(同步到数据库)
python3 manage.py makemigrations 记录数据库迁移
仅仅是在 migrations 文件夹中 记录数据库的修改,并不会直接操作数据库
在当前 app 的 migration 文件夹下会多出一个 .py 文件(记录数据库更改)
python3 manage.py migrate 将数据库修改记录(migrations 中的记录)真正同步到数据库
要等一会儿(第一次执行数据库迁移(还是同步啊?没试)命令会自动创建一堆表(django需要依赖的表),后续就是更新多出来的这几张表的记录了)

简便写法

这里写会有提示,但还是要会自己完整写, 万一面试让手写呢?
makemigrations 记录数据库迁移
会产生类似如下的文件
app01/migrations/0008_auto_20190916_2358.py
# -*- coding: utf-8 -*-
# Generated by Django 1.11.11 on 2019-09-16 23:58
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app01', '0007_remove_user_addr'),
]
operations = [
migrations.AlterField(
model_name='user',
name='password',
field=models.IntegerField(),
),
]
首次创建表时(写模型类时)
app01/migrations/0001_initial.py
# -*- coding: utf-8 -*-
# Generated by Django 1.11.11 on 2019-09-16 04:29
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='User',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('username', models.CharField(max_length=32)),
('password', models.IntegerField()),
],
),
]
migrate 同步到数据库
新增或者更新新出的那些 表的记录

注意
只要动了models 中跟数据库相关的代码,就必须重新执行上面的两条命令,缺一不可
特殊点--表名会自动加上模块的前缀
自动加前缀,可以方便协同开发,解耦合,合在一起就行了(那大家都创 app01 呢?)
表字段的增删改
改完后必须执行数据库迁移的那两条命令
而且一般也不会让你去动表结构,表是在开发之前就要定下来的!
增加表字段
当表里已经有记录时,后续还要想添加字段,需要指定默认值 或者 允许新增字段为空
1.给新增的字段设置默认值
addr = models.CharField(max_length=32,default='China') # default该字段默认值
2.给新增的字段设置成可以为空
age = models.IntegerField(null=True) # 该字段允许为空
当没有记录 或者 表还未被创建时,则不会有上述问题
删除表字段
- 直接在表模型类里 加注释 / 删除
- 重新执行两条命令即可
强调!:执行完之后,表中该字段所对应的所有数据全部清空
---》 没事儿别瞎注释!或者删除(这不仅仅是python代码,还牵连着数据库)
并且一般也不会真正意义上的删除(除非设计不合理)
改字段
结合新增字段和删除字段(小推测,未实践)
数据的增删改查(ORM)
导入 models 里面的表
查数据(跟前面手动封装的一样)
from app01 import models # ORM操作需要使用 models 类中的名字
查记录
get(拿到一个对象,对象没有会报错,不推荐)
models.User.objects.get(username=username, 条件2)

filter(拿到列表,可以放多个参数(条件))
models.User.objects.filter(username=username, password=password, 条件3)
返回的是一个列表(QuerySet),里面放的才是一个个的对象
当查询条件不存在时,不会报错,只会返回一个空列表
filter 括号内支持写多个参数,并且参数之间是 and 关系
print(res.query)可以打印查询语句(只有 QuerySet 对象才可以直接查看内部对应的 sql 语句) orm 暂时做个了解,后面有详解QuerySet 对象你可以把它当成列表操作,索引也可以用索引取,但是不推荐这么做( QuerySet 只支持整数索引,不支持负数) 还支持切片操作(也不支持负数,切出来的结果还是一个 QuerySet 对象)
QuerySet 封装的方法(个别)
..... filter().first() 拿列表中的第一个对象
空列表不会报错
不推荐你使用索引取值,一旦没有任何数据,再索引取值会报错,但是如果用 .first() 虽然内部也是按索引取值,但是没有数据, 也不会报错,返回的是None
models.User.objects.filter(username=username).first()
少了 .first() 会报这个错

all (拿到所有的)
models.User.objects.all() 直接拿到 User 表模型类的所有数据,结果是列表套对象
增加记录
新增对象的两种方式
create 方法
models.User.objects.create(username=username, password=password)
create方法能够新增数据并且有一个返回值
返回值就是新增的数据对象本身
实例化对象调用 .save()
...省略一堆代码
user_obj = models.User(username=username, password=password)
user_obj.save()
...省略一堆代码
删除记录
models.User.objects.filter(条件).delete()
html中利用 a 标签的 href 把参数发过去(加一个删除功能)
models.User.objects.filter(条件).delete()

更新记录
无论是什么请求,request.GET 都能拿到 url 里携带的参数

总体思路
先传过来id
获取记录 重定向到页面让用户修改
获取用户提交过来的新信息,更新数据,重定向到列表页
.filter(条件).update(username=username, password=password) 批量更新
models.User.objects.filter(id=edit_id).update(username=username,password=password)
.filter 拿到的是一个列表,所以 .filter 的操作 都是批量操作(如果 .filter 结果列表中有多个数据,那么会一次性全部修改,就类似于 for循环一个个修改)
直接 对象.改属性 .save保存
edit_obj.username = username
edit_obj.password = password
edit_obj.save()
不推荐!--> 会从头到尾将所有的字段修改一遍(遍历身上的属性),效率极低
用户信息增删改查
先通过 orm 展示所有的数据到前端
all() 拿所有数据
模板语法 for 循环
添加新增按钮,能够实现用户的新增操作
利用 a 标签的 href 直接触发后端的逻辑
添加编辑、删除按钮
编辑
删除
利用 get 请求携带参数的特点,在url的后面跟上对应数据的id值
request.GET.get()
如果是编辑
重新渲染一个页面,将编辑对象传递到前端,让用户修改
如果是删除
直接利用 filter(条件).delete()
重定向定位不同的页面
与ORM相关的代码实现
app01/views.py
from django.shortcuts import render, HttpResponse, redirect
from app01 import models
# Create your views here.
def login(request):
# 视图函数针对不同的请求方式 应该有不同的处理逻辑
# if request.method == 'GET':
# print('收到了')
# print(request.method) # 能够获取前端请求方式 并且是全大写的字符串
# print(type(request.method))
# return render(request,'login.html')
# elif request.method == 'POST':
# # 获取用户输入 做相应的逻辑判断
# return HttpResponse("拿到了 老弟")
if request.method == 'POST':
print(request.POST) # 获取前端post请求提交过来的数据 就把它当成一个大字典即可
# <QueryDict: {'username': ['jason', 'zekai'], 'password': ['123']}>
username = request.POST.get('username') # 默认取列表最后一个元素
# password = request.POST['password'] # 不推荐 使用
password = request.POST.get('password')
# hobby = request.POST.getlist('hobby')
# print(username,password,hobby)
# print(type(username),type(password),type(hobby))
# 利用orm从数据库获取数据 校验
# 1.查询数据
# 1.1 get()
# user_obj = models.User.objects.get(username=username) # select * from user where username='jason'
# """
# get方法 能够直接拿到数据对象本身 但是 当查询条件不存在的时候 会直接报错 所有不推荐使用
# """
# print(user_obj)
# print(user_obj.username)
# print(user_obj.password)
# 1.2 filter()
# res = models.User.objects.filter(username=username,password=password)
"""
filter查询出来的结果是一个"列表 列表内放的才是一个个的数据对象本身"
当查询条件不存在的时候 不会报错 只会返回一个空列表
filter括号内 支持写多个参数 并且参数与参数之间是and的关系
"""
# print(res.query) # 只有querySet对象才可以直接点query查看年内部对应的sql语句
# 1.filter拿到的结果就是一个querySet对象(你现在只需要知道filter拿到的结果就能够点query查看sql语句)
"""
SELECT `app01_user`.`id`, `app01_user`.`username`, `app01_user`.`password`
FROM `app01_user`
WHERE (`app01_user`.`username` = jason AND `app01_user`.`password` = 123)
"""
# print(res)
# user_obj = res[0:2]
"""
querySet对象 你可以吧它当做列表操作 取值也可以通过索引取(querySet只支持正数索引 不支持负数) 还支持切片操作(切出来的结果还是一个querySet对象)
但是不推荐你这么做
"""
user_obj = models.User.objects.filter(username=username).first() # 拿列表中第一个数据对象
"""
不推荐你使用索引取值 原因在于一旦没有任何数据 再索引取值会报错
但是如果用first虽然内部也是按照索引取值 但是没有数据 也不会报错 返回的是None
"""
# print(user_obj,user_obj.username,user_obj.password)
if user_obj:
if user_obj.password == password:
return redirect('http://www.xiaohuar.com')
return HttpResponse('用户不存在 ')
print(request.GET) # 如果没有get请求携带的数据 就是一个空字典
print(request.GET.get('username'))
print(request.GET.getlist('hobby'))
return render(request, 'login.html')
"""
http://127.0.0.1:8000/static/bootstrap-3.3.7-dist/css/bootstrap.min.css
"""
def reg(request):
if request.method == 'POST':
username = request.POST.get("username")
password = request.POST.get('password')
# orm插入数据
# 1.create()
# res = models.User.objects.create(username=username,password=password) # insert into user(username,password) values(username,password)
# """
# create方法能够新增数据 并且有一个返回值
# 返回值就是新增的数据对象本身
# """
# print(res)
# print(res.username)
# print(res.password)
# 2.利用对象
user_obj = models.User(username=username, password=password)
user_obj.save()
return render(request, 'reg.html')
def user_list(request):
# 将user表中的数据全部查出
data = models.User.objects.all() # select * from user
"""
拿到的也是一个querySet对象
"""
print(data.query)
return render(request, 'userlist.html', {'user_list': data})
def del_user(request):
# 根据用户想要删除的数据的id值 取数据库中删除数据
# 获取到id值
delete_id = request.GET.get('id')
# 拿着id去数据库中删除
models.User.objects.filter(id=delete_id).delete() # delete from user where id = delete_id;
return redirect('/userlist/')
def update_user(request):
# 编辑 是基于已经存在了的数据 进行一个修改
# 逻辑:获取用户想要修改的数据的主键值 然后去数据库修改数据
edit_id = request.GET.get('id')
# 给用户将数据查出来 展示到页面上 让用户自己修改
edit_obj = models.User.objects.filter(id=edit_id).first()
# 将编辑对象传递给前端页面
if request.method == 'POST':
# 不要关系思维 post请求中也是获取get请求携带的参数
username = request.POST.get('username')
password = request.POST.get('password')
# 更新数据
# 方式1:
# models.User.objects.filter(id=edit_id).update(username=username,password=password)
# update user set username = username,password = password where id = edit_id
"""
filter拿到是一个列表 filter操作其实都是批量操作
如果filter结果列表中有多个数据 那么会一次性全部修改
类似于for循环一个个修改
"""
# 方式二(不推荐使用)
edit_obj.username = username
edit_obj.password = password
edit_obj.save()
"""
第二种方式会从头到尾将所有的字段全部修改一遍 效率极低
"""
return redirect('/userlist/')
return render(request, 'update_user.html', {"edit_obj": edit_obj})
def test_request_way(request):
print(request.method, type(request.method))
# GET <class 'str'>
return HttpResponse('alallala')
代码书写位置--个人小总结(待补充)
--> 暨 django 目录结构再解读
为了防止后期搞混,不知道代码往哪写,所以最好还是把,每个文件写在哪的搞清楚(app 里面还是项目同名文件夹下?)
app文件下的
views.py 视图函数/类 一般都是分应用(某个方面)来对应功能(视图函数)的
models.py 数据库模型类,一般还会给模型类加上app的前缀(django设计的是可以分开开发,最后合并,故这里这样做能保证数据表名不重复(那app名字一样呢...))
项目同名文件下的
urls.py 路由配置
settings.py django暴露给用户可以配置的配置信息,这里包含了 app 注册、templates 路径配置、static 静态资源路径配置等
app 和 项目同名目录 都可以放的
单独拎出来可能记得更深点吧
__init__.py 前面指定数据库软件的
import pymysql
pymysql.install_as_MySQLdb()
项目根目录的
static 静态资源文件夹,要记得改配置(settings.py、html引入的时候用static文件路径动态解析)
templates 模版文件夹,要记得配置(settings.py)
大多通过 manage.py 执行 django 的命令
--> 这个文件专门用来读取命令行命令,并作出处理
Django-开放静态资源-获取请求携带的数据-pychram连接数据库-修改Django默认数据库-DjangoORM操作--表管理-记录管理-01的更多相关文章
- zzy:请求静态资源和请求动态资源, src再次请求服务器资源
[总结可以发起请求的阶段:请求动态资源:通过web.xml匹配action然后,自定义Servlet处理该action1)form表单提交请求的时候,用action设定,该页面发起请求的Servlet ...
- Django的静态资源
如果你的静态资源是某个APP专属,那么就在这个APP目录下建立一个static目录,就像上图report这个APP中的static目录.当浏览这个APP的网页时它会从这里去找资源,当然,它首先会从共用 ...
- django 访问静态资源
urlpatterns = patterns('', url(r'^$', views.show, name='index'), url(r'^static/(?P<path>.*)', ...
- 解决Django项目静态资源无法访问的问题
静态资源无法访问 url.py中配置 from django.conf.urls import url from django.views import static from django.conf ...
- django中静态资源
创建静态资源存放路径,为了设置静态媒体,你需要设立存储它们的目录.在你的项目目录(例如/myproject/),创建叫做static的目录.在static里再创建一个images目录和js目录 设置项 ...
- django搭建一个小型的服务器运维网站-查看和修改服务器配置与数据库的路由
目录 项目介绍和源码: 拿来即用的bootstrap模板: 服务器SSH服务配置与python中paramiko的使用: 用户登陆与session; 最简单的实践之修改服务器时间: 查看和修改服务器配 ...
- Node.js——开放静态资源原生写法
借助了mime第三方包,根据请求地址请求的文件后缀,设置content-type
- [Java][Web]Request 获取请求头和数据
获取方式一 InputStream in = request.getInputStream(); int len = 0; byte buffer[] = new byte[1024]; while( ...
- [Django框架 - 静态文件配置、request对象方法初识、 pycharm链接数据库、ORM实操增删改查、django请求生命周期]
[Django框架 - 静态文件配置.request对象方法初识. pycharm链接数据库.ORM实操增删改查.django请求生命周期] 我们将html文件默认都放在templates文件夹下 将 ...
随机推荐
- 二、java实现多线程的方式?
一.同步?异步? 下面两幅图解释了同步异步. 二.实现多线程的方式 1.继承Thread package threaddemo; class CreateThreadDemo extends Thre ...
- centos部署oracle rac单实例11.2.0.3数据库(使用asm磁盘)
部署oracle rac单实例数据库,需要安装grid和datavase两部分,所以首先创建两个用户oracle和grid,因为不能使用root用户进行安装,在安装之前首先需要修改一些系统参数和安装一 ...
- Spark 系列(九)—— Spark SQL 之 Structured API
一.创建DataFrame和Dataset 1.1 创建DataFrame Spark 中所有功能的入口点是 SparkSession,可以使用 SparkSession.builder() 创建.创 ...
- react父组件调用子组件中方法
- app登录接口请求报:“签名验证失败”???已解决
根据抓包数据获得url.param.header,在charles中compose请求结果为成功,在pycharm中运行则报:“签名验证失败”. 运行结果:
- RobotFrameWork Web自动化测试环境搭建
前言 Robot Framework是一款python编写的功能自动化测试框架.具备良好的可扩展性,支持关键字驱动,可以同时测试多种类型的客户端或者接口,可以进行分布式测试执行.主要用于轮次很多的验收 ...
- freemarker导出复杂样式的Excel
freemarker导出复杂样式的Excel 代码地址: gitee https://gitee.com/suveng/demo/tree/master/chapter.002 代码存放于demo下面 ...
- java JVM原理讲解和调优和gc
- 随笔编号-04 AngularJS 相关小问题解决方案合集
1 解决 Select选择框遍历时,出现一个空白选项: <select style="width: 20%;margin-left: 5px;height: 31px;" ...
- Liunx软件安装之JDK
在安装 jdk 之前我们需要先了解下 openjdk 跟 oracle jdk 的区别. OpenJDK 是 JDK 的开源码版本,以 GP L 协议的形式发布.在 JDK7 的时候,OpenJDK ...