yii验证系统学习记录,基于yiicms(一)写的太长了,再写一篇(二)
项目地址:https://gitee.com/templi/yiicms 感谢七觞酒大神的付出,和免费分享。当然也感谢yii2的开发团队们。
项目已经安全完毕,不知道后台密码,这种背景下,后台无法进去。绕不开的话题就是:
1.后台密码账号如何产生。类似下图:
加密过的字符串自然不能用于登陆。
我尝试通过前台注册一个账户,然后登陆,因为权限不够,尽管等登陆到后台首页,同样无权访问其他任何页面。配置了下modules,
意图通过给予权限系统权限,然后更改刚加入的用户“zhuangli”以管理员角色以及权限分配等。不成功。
我们先来梳理第一个问题,yii2的密码到底是如何产生的?
我们从登陆这里开始,看它一步步都做了什么操作。
只要用户访问,必须经过yii2入口文件index.php,也就是在这个时候新创建了一个application实例,使用了配置文件中的各种配置项以及系统默认给定的几个包括响应组件,请求组件,错误组件等核心组件的实例,附着在该应用上,方便随时供访问。其中这里配置了一个user,当然不配置使用系统默认也是可以的。
'user' => [
'identityClass' => 'common\models\User',
'enableAutoLogin' => true,
'identityCookie' => ['name' => '_identity-backend', 'httpOnly' => true],
],
这个组件规定了权限类,是否自动登陆以及权限验证cookie
User is the class for the `user` application component that manages the user authentication status.
*
* You may use [[isGuest]] to determine whether the current user is a guest or not.
* If the user is a guest, the [[identity]] property would return `null`. Otherwise, it would
* be an instance of [[IdentityInterface]].
*
* You may call various methods to change the user authentication status:
*
* - [[login()]]: sets the specified identity and remembers the authentication status in session and cookie;
* - [[logout()]]: marks the user as a guest and clears the relevant information from session and cookie;
* - [[setIdentity()]]: changes the user identity without touching session or cookie
* (this is best used in stateless RESTful API implementation).
*
* Note that User only maintains the user authentication status. It does NOT handle how to authenticate
* a user. The logic of how to authenticate a user should be done in the class implementing [[IdentityInterface]].
* You are also required to set [[identityClass]] with the name of this class.
*
* User is configured as an application component in [[\yii\web\Application]] by default.
* You can access that instance via `Yii::$app->user`.
*
* You can modify its configuration by adding an array to your application config under `components`
* as it is shown in the following example:
*
* ```php
* 'user' => [
* 'identityClass' => 'app\models\User', // User must implement the IdentityInterface
* 'enableAutoLogin' => true,
* // 'loginUrl' => ['user/login'],
* // ...
* ]
* ```
*
* @property string|int $id The unique identifier for the user. If `null`, it means the user is a guest. This
* property is read-only.
* @property IdentityInterface|null $identity The identity object associated with the currently logged-in
* user. `null` is returned if the user is not logged in (not authenticated).
* @property bool $isGuest Whether the current user is a guest. This property is read-only.
* @property string $returnUrl The URL that the user should be redirected to after login. Note that the type
* of this property differs in getter and setter. See [[getReturnUrl()]] and [[setReturnUrl()]] for details.
*
翻译一下这段对user这个组件的说明:
这是一个user应用组件的类,管理用户的认证状态。可以使用isGuest(实际是getIsGuest)来辨别当前用户是否用游客。如果为游客,identity属性返回null,否则就是IdentityInterface接口的实例。有很多方法可以改变认证状态。
login,设置特定的身份,并将认证状态存在session或cookie中。
loginout,标示为游客,并将有关的信息从session或cookie中清除。
setIndentiy,只改变用户身份,不涉及session和cookie。这最好用于无状态的REST API实现。
User 仅仅用于维护用户认证状态,它并不负责如何去认证一个用户。如何去认证一个用户的逻辑应在继承至IdentityInterface类中去完成,User这个类也被要求设置为identityClass属性的值。正如这里做的:
它是被默认配置为yii\web\application的一个应用组件,正如我上面所说。可以直接通过Yii::$app->user访问到该组件。当然可以改变配置,通过在配置文件中的components底下加入数组,类似:
'user' => [
'identityClass' => 'app\models\User', // User must implement the IdentityInterface
'enableAutoLogin' => true,
'loginUrl' => ['user/login'],
// ...
]
$id唯一身份标示,为null,代表是游客,只读。$identity关联到当前登入用户的认证对象,null代表未登入(未认证)。$isGuest,当前用户是否游客,只读。$returnUrl,登陆后重定向的url。 继续看登陆的过程。
1 /**
2 * Login action.
3 *
4 * @return string
5 */
6 public function actionLogin()
7 {
8 $this->layout = false;
9 var_dump(Yii::$app->user);
10
11 if (!Yii::$app->user->isGuest) {
12 return $this->goHome();
13 }
14
15 $model = new LoginForm();
16 if ($model->load(Yii::$app->request->post()) && $model->login()) {
17 return $this->goBack();
18 } else {
19 return $this->render('login', [
20 'model' => $model,
21 ]);
22 }
23 }
首先是判断用户是否游客,不是,重定向到主页去,新建一个loginForm模型实例,这是个登陆表单的虚拟数据模型,将username和password加载到这个model中,验证执行登陆login操作。
/**
* Logs in a user using the provided username and password.
*
* @return bool whether the user is logged in successfully
*/
public function login()
{
if ($this->validate()) {
return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);
} else {
return false;
}
}
开步就是验证,这个validate方法是该类的父类model上的方法。
validate点进去是以下这样一个方法: 1 /** 2 * Performs the data validation.
*
* This method executes the validation rules applicable to the current [[scenario]].
* The following criteria are used to determine whether a rule is currently applicable:
*
* - the rule must be associated with the attributes relevant to the current scenario;
* - the rules must be effective for the current scenario.
*
* This method will call [[beforeValidate()]] and [[afterValidate()]] before and
* after the actual validation, respectively. If [[beforeValidate()]] returns false,
* the validation will be cancelled and [[afterValidate()]] will not be called.
*
* Errors found during the validation can be retrieved via [[getErrors()]],
* [[getFirstErrors()]] and [[getFirstError()]].
*
* @param array $attributeNames list of attribute names that should be validated.
* If this parameter is empty, it means any attribute listed in the applicable
* validation rules should be validated.
* @param bool $clearErrors whether to call [[clearErrors()]] before performing validation
* @return bool whether the validation is successful without any error.
* @throws InvalidParamException if the current scenario is unknown.
*/
public function validate($attributeNames = null, $clearErrors = true)
{
//清除错误
if ($clearErrors) {
$this->clearErrors();
}
//前置验证
if (!$this->beforeValidate()) {
return false;
}
//取回场景列表,该方法返回一个场景列表和活跃属性,活跃属性是指当前场景中需要验证的。格式:
```php
* [
* 'scenario1' => ['attribute11', 'attribute12', ...],
* 'scenario2' => ['attribute21', 'attribute22', ...],
* ...
* ]
默认情况下,活跃属性被认为安全,可以批量指定。如果不在批量指定之列,则认为不安全,这样请加一个!作为前缀。这个方法的默认实现会返回所有在rules中能找到的场景声明,一个特别的场景
是SCENARIO_DEFAULT,包括rules中的所有场景。每个场景将都通过运用到场景的验证规则关联到被验证的属性。
$scenarios = $this->scenarios();
$scenario = $this->getScenario();
if (!isset($scenarios[$scenario])) {
throw new InvalidParamException("Unknown scenario: $scenario");
} if ($attributeNames === null) {
$attributeNames = $this->activeAttributes();
} foreach ($this->getActiveValidators() as $validator) {
$validator->validateAttributes($this, $attributeNames);
}
$this->afterValidate(); return !$this->hasErrors();
}
注释翻译:这是一个执行数据验证的方法,这个方法将验证规则应用到当前场景,下面的标准用以决定规则当前是否可用。
规则必须将属性关联到当前场景。规则必须对当前场景有效。
这个方法前后都要调用beforeValidate和afterValidate。中间产生的错误可由getErrors,[[getFirstErrors()]] and [[getFirstError()]]取得。$attributeNames,用以验证的属性列表,如果参数为空,那意味着可应用的规则中的属性都要被验证。也即是这
public function getValidators()
{
if ($this->_validators === null) {
$this->_validators = $this->createValidators();
}
return $this->_validators;
}
注释释义:
个参数指定哪些是需要被验证的,不指定就验证所有。
场景的使用方法参考:Yii2 - 场景scenarios用法
捋一下,场景中如果没有在后代model中重写scenarios,那么在所有场景(action)都会执行所有rules指定字段的所有验证(同一字段存在多种验证,同一验证也可能应用到多个字段)。那么场景指定各个场景要验证的字段后,rules中就要用on关键字将指定场景关联到该条rules,这样场景跟验证规则跟字段就一一对应起来了,如果没有on指定场景,那就是应用到所有场景。在controller中应用某场景还需要使用$model->setScenario('update')或者$model->scenario = 'update'来应用。
$this->scenarios();中有一个方法$this->getValidators(),获取验证器。
返回rules中声明的验证器,不同于getActiveValidators的是,这个只返回应用到当前场景的验证器。因为它的返回结果是一个ArrayObject,因此可以手动插入或移除,在model behaviors中很有用。
接下来:
/**
* Creates validator objects based on the validation rules specified in [[rules()]].
* Unlike [[getValidators()]], each time this method is called, a new list of validators will be returned.
* @return ArrayObject validators
* @throws InvalidConfigException if any validation rule configuration is invalid
*/
public function createValidators()
{
$validators = new ArrayObject;
foreach ($this->rules() as $rule) {
if ($rule instanceof Validator) {
$validators->append($rule);
} elseif (is_array($rule) && isset($rule[0], $rule[1])) { // attributes, validator type
$validator = Validator::createValidator($rule[1], $this, (array) $rule[0], array_slice($rule, 2));
$validators->append($validator);
} else {
throw new InvalidConfigException('Invalid validation rule: a rule must specify both attribute names and validator type.');
}
}
return $validators;
}
通过rules中指定的验证规则创建相应验证器。再看看Validator::createValidator方法。
/**
* Creates a validator object.
* @param string|\Closure $type the validator type. This can be either:
* * a built-in validator name listed in [[builtInValidators]];
* * a method name of the model class;
* * an anonymous function;
* * a validator class name.
* @param \yii\base\Model $model the data model to be validated.
* @param array|string $attributes list of attributes to be validated. This can be either an array of
* the attribute names or a string of comma-separated attribute names.
* @param array $params initial values to be applied to the validator properties.
* @return Validator the validator
*/
public static function createValidator($type, $model, $attributes, $params = [])
{
$params['attributes'] = $attributes; if ($type instanceof \Closure || $model->hasMethod($type)) {
// method-based validator
$params['class'] = __NAMESPACE__ . '\InlineValidator';
$params['method'] = $type;
} else {
if (isset(static::$builtInValidators[$type])) {
$type = static::$builtInValidators[$type];
}
if (is_array($type)) {
$params = array_merge($type, $params);
} else {
$params['class'] = $type;
}
} return Yii::createObject($params);
}
$attribute即被验证的字段。$type指验证类,比如required,unique等,可以是闭包,可以是model上自定义的方法,将创建一个内联验证器,也可以是内置的若干验证器,或者是个带有指定class的数组,根据那个class以及其中的验证方法来验证,很灵活很强大。最后一种就是直接就是指定的type本身就是一个类。这是内联验证器的默认方式。
public static $builtInValidators = [
'boolean' => 'yii\validators\BooleanValidator',
'captcha' => 'yii\captcha\CaptchaValidator',
'compare' => 'yii\validators\CompareValidator',
'date' => 'yii\validators\DateValidator',
'datetime' => [
'class' => 'yii\validators\DateValidator',
'type' => DateValidator::TYPE_DATETIME,
],
'time' => [
'class' => 'yii\validators\DateValidator',
'type' => DateValidator::TYPE_TIME,
],
'default' => 'yii\validators\DefaultValueValidator',
'double' => 'yii\validators\NumberValidator',
'each' => 'yii\validators\EachValidator',
'email' => 'yii\validators\EmailValidator',
'exist' => 'yii\validators\ExistValidator',
'file' => 'yii\validators\FileValidator',
'filter' => 'yii\validators\FilterValidator',
'image' => 'yii\validators\ImageValidator',
'in' => 'yii\validators\RangeValidator',
'integer' => [
'class' => 'yii\validators\NumberValidator',
'integerOnly' => true,
],
'match' => 'yii\validators\RegularExpressionValidator',
'number' => 'yii\validators\NumberValidator',
'required' => 'yii\validators\RequiredValidator',
'safe' => 'yii\validators\SafeValidator',
'string' => 'yii\validators\StringValidator',
'trim' => [
'class' => 'yii\validators\FilterValidator',
'filter' => 'trim',
'skipOnArray' => true,
],
'unique' => 'yii\validators\UniqueValidator',
'url' => 'yii\validators\UrlValidator',
'ip' => 'yii\validators\IpValidator',
];
内联的有以上这么多方法。
/**
* Returns the attribute names that are subject to validation in the current scenario.
* @return string[] safe attribute names
*/
public function activeAttributes()
{
$scenario = $this->getScenario();
$scenarios = $this->scenarios();
if (!isset($scenarios[$scenario])) {
return [];
}
$attributes = $scenarios[$scenario];
foreach ($attributes as $i => $attribute) {
if ($attribute[0] === '!') {
$attributes[$i] = substr($attribute, 1);
}
} return $attributes;
}
返回从属于当前场景的安全属性名列表。
返回应用到当前场景的验证器。$attribute是指需要返回验证器的属性名。如果为null,所有model中的属性将返回。
foreach ($this->getActiveValidators() as $validator) {
$validator->validateAttributes($this, $attributeNames);
}
这个循环对当前场景活跃属性进行验证,验证代码如下:
/**
* Validates the specified object.
* @param \yii\base\Model $model the data model being validated
* @param array|null $attributes the list of attributes to be validated.
* Note that if an attribute is not associated with the validator - it will be
* ignored. If this parameter is null, every attribute listed in [[attributes]] will be validated.
*/
public function validateAttributes($model, $attributes = null)
{
if (is_array($attributes)) {
$newAttributes = [];
foreach ($attributes as $attribute) {
if (in_array($attribute, $this->getAttributeNames(), true)) {
$newAttributes[] = $attribute;
}
}
$attributes = $newAttributes;
} else {
$attributes = $this->getAttributeNames();
} foreach ($attributes as $attribute) {
$skip = $this->skipOnError && $model->hasErrors($attribute)
|| $this->skipOnEmpty && $this->isEmpty($model->$attribute);
if (!$skip) {
if ($this->when === null || call_user_func($this->when, $model, $attribute)) {
$this->validateAttribute($model, $attribute);
}
}
}
}
验证指定的对象,第一个参数$model,要验证的model,第二个参数要被验证的属性列表。注意如果属性没有没有关联到验证器会忽略,如果这个参数为空,attributes中的属性都会被验证。
对scenarios方法的详解:
/**
* Returns a list of scenarios and the corresponding active attributes.
* An active attribute is one that is subject to validation in the current scenario.
* The returned array should be in the following format:
*
* ```php
* [
* 'scenario1' => ['attribute11', 'attribute12', ...],
* 'scenario2' => ['attribute21', 'attribute22', ...],
* ...
* ]
* ```
*
* By default, an active attribute is considered safe and can be massively assigned.
* If an attribute should NOT be massively assigned (thus considered unsafe),
* please prefix the attribute with an exclamation character (e.g. `'!rank'`).
*
* The default implementation of this method will return all scenarios found in the [[rules()]]
* declaration. A special scenario named [[SCENARIO_DEFAULT]] will contain all attributes
* found in the [[rules()]]. Each scenario will be associated with the attributes that
* are being validated by the validation rules that apply to the scenario.
*
* @return array a list of scenarios and the corresponding active attributes.
*/
public function scenarios()
{
$scenarios = [self::SCENARIO_DEFAULT => []];
//先做一遍清空,循环类数组对象
foreach ($this->getValidators() as $validator) {
//rules中指定的on场景清空
foreach ($validator->on as $scenario) {
$scenarios[$scenario] = [];
}
//rules中指定的except场景清空
foreach ($validator->except as $scenario) {
$scenarios[$scenario] = [];
}
} //场景变量中的第一个为self::SCENARIO_DEFAULT,后面依次为上面循环的on和except中的场景
//这些场景应该指活跃场景,这些场景是需要验证的,其他不必。
$names = array_keys($scenarios); //此处对验证器循环,检查未绑定有和排除了验证的场景,全部置真。
//而未绑定有,并且不在绑定了排除验证场景的,置真。就是说这些是需要验证的。
//检查有绑定场景,则将这些置真来验证,其他的不验证。
foreach ($this->getValidators() as $validator) {
if (empty($validator->on) && empty($validator->except)) {
foreach ($names as $name) {
//rules中没有指定on和except,那$names就只有default
//此时会将验证器上所有的属性循环到$scenarios['default']中去。
//意即所有的属性在所有场景都要验证
foreach ($validator->attributes as $attribute) {
$scenarios[$name][$attribute] = true;
}
}
} elseif (empty($validator->on)) {
//rules中on为空,except设置
foreach ($names as $name) {
//不在except中,并且在rules中,在场景中设置真。不在场景中的根本不进入这个验证列表。
//结果还是留下default,实际情况也是如此,所有场景都不验证,符合逻辑
if (!in_array($name, $validator->except, true)) {
foreach ($validator->attributes as $attribute) {
$scenarios[$name][$attribute] = true;
}
}
}
} else {
//这里会留下on绑定的场景的属性。除外的就被排除了。
foreach ($validator->on as $name) {
foreach ($validator->attributes as $attribute) {
$scenarios[$name][$attribute] = true;
}
}
}
} //上面是跟rules所限定的验证器比对,在的并符合需要验证条件的置真。
//然后与场景list中的设置进行比较,过滤调场景中没有的属性
foreach ($scenarios as $scenario => $attributes) {
if (!empty($attributes)) {
$scenarios[$scenario] = array_keys($attributes);
}
} return $scenarios;
}
/**
* Returns the validators applicable to the current [[scenario]].
* @param string $attribute the name of the attribute whose applicable validators should be returned.
* If this is null, the validators for ALL attributes in the model will be returned.
* @return \yii\validators\Validator[] the validators applicable to the current [[scenario]].
*/
public function getActiveValidators($attribute = null)
{
$validators = [];
$scenario = $this->getScenario();
foreach ($this->getValidators() as $validator) {
if ($validator->isActive($scenario) && ($attribute === null || in_array($attribute, $validator->getAttributeNames(), true))) {
$validators[] = $validator;
}
}
return $validators;
}
以上返回应用到当前场景的验证器,$attribute指定要返回的验证器属性名。如果为null,所有的都返回。这里先获取到场景名,默认是default,然后循环当前model上的验证器,如果在
当前这个场景验证器活跃,并且传入的属性为null,或者该属性存在于验证器上,写入验证器数组。
/**
* Returns a value indicating whether the validator is active for the given scenario and attribute.
*
* A validator is active if
*
* - the validator's `on` property is empty, or
* - the validator's `on` property contains the specified scenario
*
* @param string $scenario scenario name
* @return bool whether the validator applies to the specified scenario.
*/
public function isActive($scenario)
{
return !in_array($scenario, $this->except, true) && (empty($this->on) || in_array($scenario, $this->on, true));
}
返回一个代表验证器在给定场景和属性上是否激活。激活的判断标准是,验证器的on属性为空,或者on属性包含指定的场景。
/**
* Returns cleaned attribute names without the `!` character at the beginning
* @return array attribute names.
* @since 2.0.12
*/
public function getAttributeNames()
{
return array_map(function($attribute) {
return ltrim($attribute, '!');
}, $this->attributes);
}
在开始返回不带有!的干净的属性名。
/**
* Validates the specified object.
* @param \yii\base\Model $model the data model being validated
* @param array|null $attributes the list of attributes to be validated.
* Note that if an attribute is not associated with the validator - it will be
* ignored. If this parameter is null, every attribute listed in [[attributes]] will be validated.
*/
public function validateAttributes($model, $attributes = null)
{
if (is_array($attributes)) {
$newAttributes = [];
foreach ($attributes as $attribute) {
if (in_array($attribute, $this->getAttributeNames(), true)) {
$newAttributes[] = $attribute;
}
}
$attributes = $newAttributes;
} else {
$attributes = $this->getAttributeNameas();
} foreach ($attributes as $attribute) {
$skip = $this->skipOnError && $model->hasErrors($attribute)
|| $this->skipOnEmpty && $this->isEmpty($model->$attribute);
if (!$skip) {
if ($this->when === null || call_user_func($this->when, $model, $attribute)) {
$this->validateAttribute($model, $attribute);
}
}
}
}
验证的核心代码,验证指定的对象,参数$model是被验证的数据模型,$attributes要被验证的属性列表,如果他没有关联的到验证器就忽略,如果该参数为null,所有的属性都将被验证。
如果是数组,定义一个空数组,并对该数组循环,传入的就是该活跃场景下所有属性,一般为default,全部。场景中的属性如果不在验证器里面,就忽略掉,不存入新数组,如果不是数组,
就直接从验证器上取出属性。
$skip = $this->skipOnError && $model->hasErrors($attribute)
|| $this->skipOnEmpty && $this->isEmpty($model->$attribute);
定义的$this->skipOnError默认为真,$this->skipOnEmpty也为真,其他两个就是检测是否有错或者空。前两个和后两个合成的结果可以有一个为假,但必须同时为假,已经有两个属性默认为真的,那前后两个其他属性必须都为假,就是说该被验证的属性既不能为空,也不能有错。
yii验证系统学习记录,基于yiicms(一)写的太长了,再写一篇(二)的更多相关文章
- yii验证系统学习记录,基于yiicms(二)
/** * Validates the specified object. * @param \yii\base\Model $model the data model being validated ...
- 【基于WinForm+Access局域网共享数据库的项目总结】之篇二:WinForm开发扇形图统计和Excel数据导出
篇一:WinForm开发总体概述与技术实现 篇二:WinForm开发扇形图统计和Excel数据导出 篇三:Access远程连接数据库和窗体打包部署 [小记]:最近基于WinForm+Access数据库 ...
- PackageManagerService 学习记录 基于7.1.1源码
参考: http://blog.csdn.net/innost/article/details/47253179 http://blog.csdn.net/gaugamela/article/deta ...
- AM335X的SD卡更新系统学习记录
一般利用一张SD卡就能进行系统的更新,以前一直不知是什么原理,最近了解了下,对了解到的内容做个记录.使用的是AM335X平台,系统是Linux,文件系统是EXT3: 1.首先需要一张分好分区的SD卡( ...
- PHP实战-文章发布系统学习记录
跟随大师的步伐,一步一步向前行进,PHP学习之路中的历程. 如果图片不能正常查看请访问云笔记链接 http://note.youdao.com/share/?id=3c25d8c03ef946d9c6 ...
- 系统学习java高并发系列三
转载请注明原创出处,谢谢! 首先需要说说线程安全?关于线程安全一直在提,比如StringBuilder和StringBuffer有什么区别? 经常就会出现关于线程安全与线程非安全,可能一直在提自己没有 ...
- 【Python系统学习】基础篇
这次真的是最后一次了!第三次滚Python的基础.走了太多弯路.认真一点!菜鸟! 教程 转义字符 \ 可以转义很多字符,比如\n表示换行,\t表示制表符,字符\本身也要转义,所以\\表示的字符就是\ ...
- JS继续学习记录(一)
JS继续学习记录(一) 总感觉自己的js code写的还算可以,但是又深知好像只知道一些皮毛,所以打算仔细记录一下js晋级学习过程,日日往复 先记录一下自己目前对js的了解吧(20180828) js ...
- Apache Shiro 学习记录5
本来这篇文章是想写从Factory加载ini配置到生成securityManager的过程的....但是貌似涉及的东西有点多...我学的又比较慢...很多类都来不及研究,我又怕等我后面的研究了前面的都 ...
随机推荐
- myisam和innodb 删除一条记录后,再次添加后,最大记录值
- springMVC 访问静态资源
问题描述 使用SpringMVC时遇到静态资源无法加载的问题,报404 问题原因 如果SpringMVC的映射模式采用的是后缀名匹配,如[*.do]或者[*.action]则不会出现该问题,因为静态资 ...
- .net mvc C#生成网页快照
目标:调用某一网页,自动抓取整个页面为图片,并保存 public class WebSiteThumbnail { Bitmap m_Bitmap; string m_Url; public WebS ...
- POJ1149_PIGS
一共有n个猪圈,m个客人,一开始每个猪圈都有一定数量的猪猪.每个客人会打开一些猪圈,带走最多为某一个数量的猪猪,剩下的猪猪可以任意分配在这些开了的猪圈里面,然后重新关上.问所有的客人最多可以带走多少猪 ...
- 洛谷 P2431 正妹吃月饼 解题报告
P2431 正妹吃月饼 题目描述 今天是中秋节.\(uim\)带来了一堆大小不同且味道各异的月饼. 这些月饼的质量分别是\(1g\),\(2g\),\(4g\),\(8g\),\(16g\)....后 ...
- centos下安装ngnix+php+mysql服务
一.nginx 安装 1.查看yum下nginx版本信息 [root@localhost ~]# yum list | grep nginx 2.手动添加nginx的yum仓库 [root@local ...
- web服务器nginx和apache的对比分析
今天准备较详细的对比一下apache httpd与nginx两个web服务器的异同点.优缺点.由于我并不是做web开发的,所以有什么理解错误还请指出,想要了解它们是因为工作中有时候会用到它, ...
- where EXISTS (子查询)多对多中通过中间表查对方列表
用户表A,小组表B,小组和用户是多对多关系,中间有个中间表M 已知 小组 id 即teamId ,想知道这个小组中的用户列表信息,可以如下写sql: select * from A a where E ...
- 自定义ribbon规则
关于ribbon的知识:. 在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于http restful的.Spring cloud有两种服务调用方式,一种是ribbon+restT ...
- Java入门:绘制简单图形
在上一节,我们学习了如何使用swing和awt工具创建一个空的窗口,本节学习如何绘制简单图形. 基本绘图介绍 Java中绘制基本图形,可以使用Java类库中的Graphics类,此类位于java.aw ...