Java将对象保存到文件中/从文件中读取对象

1.保存对象到文件中

Java语言只能将实现了Serializable接口的类的对象保存到文件中,利用如下方法即可:

复制代码
    public static void writeObjectToFile(Object obj)
    {
        File file =new File("test.dat");
        FileOutputStream out;
        try {
            out = new FileOutputStream(file);
            ObjectOutputStream objOut=new ObjectOutputStream(out);
            objOut.writeObject(obj);
            objOut.flush();
            objOut.close();
            System.out.println("write object success!");
        } catch (IOException e) {
            System.out.println("write object failed");
            e.printStackTrace();
        }
    }
复制代码

参数obj一定要实现Serializable接口,否则会抛出java.io.NotSerializableException异常。另外,如果写入的对象是一个容器,例如List、Map,也要保证容器中的每个元素也都是实现 了Serializable接口。例如,如果按照如下方法声明一个Hashmap,并调用writeObjectToFile方法就会抛出异常。但是如果是Hashmap<String,String>就不会出问题,因为String类已经实现了Serializable接口。另外如果是自己创建的类,如果继承的基类没有实现Serializable,那么该类需要实现Serializable,否则也无法通过这种方法写入到文件中。

        Object obj=new Object();
        //failed,the object in map does not implement Serializable interface
        HashMap<String, Object> objMap=new HashMap<String,Object>();
        objMap.put("test", obj);
        writeObjectToFile(objMap);

 

2.从文件中读取对象

可以利用如下方法从文件中读取对象

复制代码
    public static Object readObjectFromFile()
    {
        Object temp=null;
        File file =new File("test.dat");
        FileInputStream in;
        try {
            in = new FileInputStream(file);
            ObjectInputStream objIn=new ObjectInputStream(in);
            temp=objIn.readObject();
            objIn.close();
            System.out.println("read object success!");
        } catch (IOException e) {
            System.out.println("read object failed");
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return temp;
    }
复制代码

读取到对象后,再根据对象的实际类型进行转换即可。

CTF_WEB题

WEB题目地址:http://ctf3.shiyanbar.com/web/good/index.php

<?php 
show_source(__FILE__); 
$a=0; 
$b=0; 
$c=0; 
$d=0; 
if (isset($_GET['x1'])) 
{ 
        $x1 = $_GET['x1']; 
        $x1=="1"?die("ha?"):NULL; 
        switch ($x1) 
        { 
        case 0: 
        case 1: 
                $a=1; 
                break; 
        } 
} 
$x2=(array)json_decode(@$_GET['x2']); 
if(is_array($x2)){ 
    is_numeric(@$x2["x21"])?die("ha?"):NULL; 
    if(@$x2["x21"]){ 
        ($x2["x21"]>2017)?$b=1:NULL; 
    } 
    if(is_array(@$x2["x22"])){ 
        if(count($x2["x22"])!==2 OR !is_array($x2["x22"][0])) die("ha?"); 
        $p = array_search("XIPU", $x2["x22"]); 
        $p===false?die("ha?"):NULL; 
        foreach($x2["x22"] as $key=>$val){ 
            $val==="XIPU"?die("ha?"):NULL; 
        } 
        $c=1; 
} 
} 
$x3 = $_GET['x3']; 
if ($x3 != '15562') { 
    if (strstr($x3, 'XIPU')) { 
        if (substr(md5($x3),8,16) == substr(md5('15562'),8,16)) { 
            $d=1; 
        } 
    } 
} 
if($a && $b && $c && $d){ 
    include "flag.php"; 
    echo $flag; 
} 
?>

题目要求传入三个参数x1,x2,x3;

首先看x1;

switch ($x1)
{
case 0:
case 1:
$a=1;
break;
}

switch语句只要不break,就会一直执行下去,所以X0时,a=1。

 

 

再看x2.

$x2=(array)json_decode(@$_GET[‘x2’]);
if(is_array($x2)){
is_numeric(@$x2[“x21”])?die(“ha?”):NULL;
if(@$x2[“x21”]){
($x2[“x21”]>2017)?$b=1:NULL;
}
if(is_array(@$x2[“x22”])){
if(count($x2[“x22”])!==2 OR !is_array($x2[“x22”][0])) die(“ha?”);
$p = array_search(“XIPU”, $x2[“x22”]);
$p===false?die(“ha?”):NULL;
foreach($x2[“x22″] as $key=>$val){
$val===”XIPU”?die(“ha?”):NULL;
}
$c=1;
}
}

 

 

x2要是数组,这里用php的json_encode()函数就可以简单转换。

 

X2中的“x21”项不能是数字,但是下面又要比2017大,这就要了解php数字和字符串的大小比较就可以了,只要前面包含比2017大的数就可以使得题目中的比较为true,那就随便选一个数字加多个a:2222a,

 

X2中的“x21”项要是包含两个项的数组,同时第一项要是一个数组,那就[1]吧

array_search(“XIPU”, $x2[“x22”]);
要求次函数返回为真,但是后面的代码要求每一项不包含XIPU,

arry_search()函数有个漏洞,当字符串不能找到时,会将他强制转化为整形再寻找,

运行intval(“XIPU”)的值为0,所以第二项为0;

 

于是x2= {“x21″:”2222a”,”x22″:[[1],0]}

 

X3是一个MD5局部碰撞,而且字符串中要包含XIPU,写个php脚本跑一下就行了

http://134.175.49.230:8888/test2.php

<?php

$t=substr(md5("15562"),8,16);

$i=15562;

while(1){

$flag="XIPU";

$flag.=$i;

$fmd5=substr(md5($flag),8,16);

if($fmd5==$t){

echo $flag."<br>";

echo $fmd5."<br>";

var_dump($fmd5==$t);

break;

}

$i++;

}

所以x3= XIPU18570

所以答案是http://ctf3.shiyanbar.com/web/good/index.php?x1=0&x2={%22×21%22:%222222a%22,%22×22%22:[[1],0]}&x3=XIPU18570

laravel定时任务以及定时函数详解

1.首先我们先创建一个Test.php测试任务

1
php artisan make:command Test

laravel5.2及以前的版本(emmmm如果没记错的话,是这样的)使用make:console命令

创建完成后会在app/Console/Commands/目录下,如图

https://img.mukewang.com/5b4db68a0001294c03420312.jpg

打开Test.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
class Test extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature 'test';//命令名称,待会调用php artisan test就会执行
    /**
     * The console command description.
     *
     * @var string
     */
    protected $description '这是一条测试任务';//命令描述,没什么用
    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();//自构函数,也用不到
    }
    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        //主要业务逻辑在这些
        Log::info('测试任务');
    }
}

然后要注册这个任务。

在Kernel.php中完成注册。

https://img.mukewang.com/5b4db7ef000178f206400341.jpg

注册完成后。我们就可以调用这里的任务了。

https://img1.mukewang.com/5b4db8290001ef4e02270057.jpg

可以在日志文件中看到

https://img1.mukewang.com/5b4db83d0001897705350121.jpg

说明我们已经成功调用了这个测试任务。

然后,我们这里着重说一下定时任务的调度。在kernel.php中还有一个schedule函数,这个就是用来做定时调度的。

https://img.mukewang.com/5b4db8af0001872908020380.jpg

我像这样我就写了每天上午9点调用这个任务。

详细说下laravel里面所有的定时函数,让你用的如鱼得水~~~~

->cron($expression)  emmm…..这个函数好像从来都没用到过,看英文介绍是“表达频率的cron表达式”,等我有时间在研究一下这个函数。

->between($startTime, $endTime)   任务在startTime和endTime时间段之内被调用,example:->between(8:00,9:00)表示8:00到9:00之间调用任务

->unlessbetween($startTime, $endTime)   任务在startTime和endTime时间段之内被调用,example:->between(8:00,9:00)表示8:00到9:00之间不调用任务

->inTimeInterval($startTime, $endTime)  同between($startTime, $endTime),因为between()最终还是去调用了inTimeInterval()这个函数

->everyMinute()  最简单的一个函数,每分钟调用一次

->everyFiveMinutes()  每5分钟调用一次

->everyTenMinutes()  每10分钟调用一次

->everyFifteenMinutes()  每15分钟调用一次

->everyThirtyMinutes()  每30分钟调用一次

->hourly()  每小时调用一次,准点调用

->hourlyAt($offset)  每小时调用一次,example: ->hourly(30)  1:30,2:30,3:30…调用一次

->daily()  每天0:00调用一次

>dailyAt($time)  example: ->daily(9:00)每天9点调用一次

->at($time) 在给定的时间调用函数

->twiceDaily($first = 1, $second = 13)  每天调用两次,默认0点和12点调用

->weekdays()  工作日调用

->weekends()  周末调用

->mondays() 周一调用

->tuesdays() 周二调用

->wednesdays() 周三掉用

->thursdays() 周四调用

->firdays() 周五调用

->saturdays() 周六调用

->sundays() 周日调用

->weekly() 每周调用一次

->weeklyOn($day, $time = ‘0:0’) example: ->weeklyOn(0, 8:00)每周日8点调用,0,7都表示周日,1-6,相对应

->monthly()  每月调用一次

->monthlyOn($day, $time = ‘0:0’) emaple: ->monthlyOn(5, 9:00) 每月5号9:00调用

->twiceMonthly($first = 1, $second = 16)  每月调用2次,如果没理解错应该是默认每月1号零点和16号零点(15号24点),没测试

->quarterly() 每季度调用一次

->yearly()  每年调用一次

 

作者:寞小陌
链接:https://www.imooc.com/article/44321
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作

laravel 第三方开发工具 IDE HELPER安装

github地址:https://github.com/barryvdh/laravel-ide-helper

安装 IDE HELPER:

composer require barryvdh/laravel-ide-helper --dev

在后面的php artisan ide-helper:models需要一个依赖,所以可以提前安装

composer require doctrine/dbal --dev

在config/app.php中的’providers’ => 添加如下类

\Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class,

执行如下命令:

php artisan ide-helper:generate

设置容器的名称映射:

php artisan ide-helper:meta

设置models的智能提示:

php artisan ide-helper:models

此时若提示要缺少doctrine/dbal

将其安装在dev下

composer require doctrine/dbal --dev

方法二:

建立command一键设置代码智能提示

php artisan make:command RunLocal

修改command(路径:App/Console/Commands/RunLocal.php)代码如下

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\App;

class RunLocal extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'run:local';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'run only local';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        if(\App::environment() === 'local'){
            \Config::set('database.connections.mysql.port',33060);
            $this->call('ide-helper:generate');
            $this->call('ide-helper:meta');
            $this->call('ide-helper:models');

        }
        //
    }
}

 

然后在Consle核心文件Kernel.php注册:

class Kernel extends ConsoleKernel
{
    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        //
        RunLocal::class
    ];

然后执行命令即可

php artisan make:command RunLocal

然后就可以进入撸代码的正确方式了,(耿直的微笑

 

MYSQL建立外键确保数据统一性,完整性

什么是外键

+——-+   ref   +——-+
|  sub  | ——> |  main |
+——-+         +——-+

从表(sub)的某列引用(ref)主表(main)的某列的值。

比方学生表有个学生编号(sid),分数表中的学生列(stu)引用学生表的学 生编号,此时对于分数表的 stu 来说。学生表的 sid 就是外键。

从表也叫外键表,主表也叫主键表、外表,列也叫字段。

所以在设计的时候。就给表1加入一个外键,这个外键就是表2中的学号字段。那么这样表1就是主表,表2就是子表

你的主从关系理解颠倒了。你的图中,表1的确是主表。表2是子表,但不是叫做给表1加入一个外键,而是给表2加入一个外键,表2中的学号 字段就叫外键,它是表1学号字段的主键。

你能够这样说:表1的学号字段是表2的外键。

外键用来干什么

你贴的图片已经解释了。

为了一张表记录的数据不要太过冗余。这和软件project的模块化思想差点儿相同类似,仅仅只是在数据库中是对表关系进行解耦,尽量让表 记录的数据单一化。就如你贴的图片中,把成绩和学生信息放在一张表中就太冗余了,成绩全然能够以学生的id作为区分标识。

为什么说外键能保持数据的一致性、完整性

你想想,你的图中的第一章表切割成了表1和表2,表2的学号引用了表1的学号字段作为外键,假设不建立外键。仅仅是和表1一样单纯性 地设立一个学号字段。那么和建立外键有什么差别呢?

比方表1中张三的学号为20140900001,那么我在表2中插数据的时候在学号字段插20140900001来记录张三的成绩不也是做到了表 的解耦了吗?

这里存在的问题是。在不设置外键的情况下。表2的学号字段和表1的学号字段是没有关联的。仅仅是你自己觉得他们有关系而已。数据库并 不觉得它俩有关系。也就是说,你在表2的学号字段插了一个值(比方20140999999),可是这个值在表1中并没有,这个时候,数据库还是允 许你插入的,它并不会对插入的数据做关系检查。然而在设置外键的情况下。你插入表2学号字段的值必需要求在表1的学号字段能找到。 同一时候。假设你要删除表1的某个学号字段。必须保证表2中没有引用该字段值的列,否则就没法删除。

这就是所谓的保持数据的一致性和完整性。你想。如 果表2还引用表1的某个学号,你却把表1中的这个学号删了,表2就不知道这个学号相应的学生是哪个学生。

数据的一致性还包含数据类型的一致性(这 个见以下就知道了)。

外键的使用规范

  1. 从表的字段必须与外键类型同样(如上。分数表 stu 的类型必须和学生表 sid 的类型同样,比方都是 int(10) 类型)
  2. 外键必须是主表的唯一键(如上。学生表 sid 是主键,而主键是唯一的。所以能够作为分数表 stu 的外键)
  3. 有关联的字段(如上,分数表之所以使用学生表的 sid 是由于两者有关联,分数表记录的是学生的分数,而学生能够用 sid 来唯 一标识)
  4. 避免使用复合键(也就是说从表能够同一时候引用多个外表的字段作为一个外键,一般不推荐这样的做法)

你的问题

  1. 假设表1有多个外键可不能够是这种情况,表2中的多个字段是表1的外键;或者说表1的多个外键是在多个表中。   都能够。由于表1的外键不一定是表2的主键,也能够是唯一键(UNIQUE)。

    比方表2有个主键 A,有个唯一键 B,表1两个字段 A’ 和 B’ 分别引用表2的 A 和 B,这就是多对多的关系了。再或者表2主键 A,表3主键 B,表1的两个字段 A’ 和 B’ 分别引用表2的 A 和表3 的 B。

  2. 这个外键能够不是表1的主键,但必须是子表的主键。(简单的说就是。假设一个字段是某个表的外键时,那么该字段必须是主键)

由于你前面就理解错了,所以这句话本身就是错的。对于从表来说,外键不一定须要作为从表的主键,外键也不一定是外表的主键,外表的唯一键就能够作 为从表的外键。