<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
>
<channel>
<title><![CDATA[杨佳乐博客]]></title> 
<atom:link href="https://www.itjiale.com/rss.php" rel="self" type="application/rss+xml" />
<description><![CDATA[一个PHP程序员,做自己喜欢做的事,帮能帮助的人,联系微信:admin_1998]]></description>
<link>https://www.itjiale.com/</link>
<language>zh-cn</language>
<generator>www.emlog.net</generator>
<item>
    <title>java 面向对象demo练习</title>
    <link>https://www.itjiale.com/post/90</link>
    <description><![CDATA[<pre><code class="language-java">public class Demo3Test1 {

    // oop练习 使用面向对象实现一个简单的银行账户系统

    public static void main(String[] args) {

        BankAccount bank1 = new BankAccount("100001","张三",0);

        bank1.displayInfo();

        // 存款
        bank1.deposit(100);

        // 取款
        bank1.withdraw(10);

        bank1.withdraw(10000);

        bank1.displayInfo();

    }

}

class BankAccount{

    private String accountNumber; // 账号
    private String owner; // 姓名
    private double balance; // 余额

    // 构造方法
    public BankAccount(String accountNumber,String owner,double balance){

        this.accountNumber = accountNumber;
        this.owner = owner;
        this.balance = balance;

    }

    // 存款方法
    public void deposit(double num){
        this.balance = this.balance + num;
    }

    // 取款方法
    public void withdraw(double num){
        if(this.balance &lt; num){
            System.out.println("余额不足");
            return;
        }
        this.balance = this.balance - num;
    }

    // 打印用户信息
    public void displayInfo(){
        System.out.println("账号："+this.accountNumber+",持有人："+this.owner+",余额："+this.balance);
    }

}
</code></pre>]]></description>
    <pubDate>Tue, 01 Apr 2025 17:20:00 +0800</pubDate>
    <dc:creator>杨佳乐</dc:creator>
    <guid>https://www.itjiale.com/post/90</guid>
</item>
<item>
    <title>java 面向对象编程OOP，封装、继承、多态、抽象、接口</title>
    <link>https://www.itjiale.com/post/89</link>
    <description><![CDATA[<pre><code class="language-java">public class Demo3 {

    // 面向对象编程
    public static void main(String[] args) {

        DemoPerson dp1 = new DemoPerson("test",20);

        System.out.println("name:"+dp1.getName());

        dp1.setName("new test");

        dp1.display();

        // 继承调用
        Dog dog1 = new Dog("小白");

        // 调用父类方法
        dog1.eat();

        // 调用子类方法
        dog1.bark();

        // 多态

//        多态的作用
//        父类引用指向子类对象，调用方法时，执行子类的实现。
//
//        提升代码的通用性，可以用同一变量表示不同子类。

//        多态的核心： ✔ 父类引用可以指向子类对象
//        ✔ 方法执行时，调用的是子类的实现（动态绑定）

        Animal animal1 = new Dog("小白狗"); // 形成多态的基础条件，前面的类型是父类 Animal
        animal1.makeSound();

        animal1 = new Cat("小黑猫"); // 切换为Cat子类
        animal1.makeSound();

        // 抽象测试
        Vechicle1 v1 = new Vechicle1();
        v1.display();
        v1.testfunc();

        Vechicle2 v2 = new Vechicle2();
        v2.display();
        v2.testfunc();

        // 接口测试
        testInter1 ti1 = new testInter1();
        ti1.display();
        ti1.success();

//        总结
//        特性    作用
//        封装    保护数据，使用 getter/setter
//        继承    代码复用，子类继承父类
//        多态    统一父类类型，调用子类方法
//        抽象    提供标准，子类实现
//        接口    定义行为，可多实现

    }

}

// 封装Person类
class DemoPerson{

    // 私有属性
    private String name;
    private int age;

    // 构造方法
    public DemoPerson(String name,int age){
        this.name = name;
        this.age = age;
    }

    // 获取name
    public String getName(){
        return name;
    }

    // 设置name
    public void setName(String name){
        this.name = name;
    }

    // 展示信息
    public void display(){
        System.out.println("my name is:"+name+",age:"+age);
    }

}

// 继承
//继承的作用
//代码复用：子类继承父类的属性和方法，避免重复代码。
//提高可扩展性：新功能可以通过继承来扩展，而不需要修改已有代码。

// 父类
class Animal{

    String name;

    public Animal(String name){
        this.name = name;
    }

    public void eat(){
        System.out.println(name + " is eating");
    }

    public void makeSound() {
        System.out.println("Animal makes a sound.");
    }
}

// 子类继承父类
class Dog extends Animal{

    public Dog(String name){
        // 调用父类构造方法
        super(name);
    }

    // 子类特有方法
    public void bark(){
        System.out.println(name + " is barking");
    }

    // 重写父类方法
    @Override //注解，推荐增加
    public void eat(){
//        重写的特点： ✔ 方法名、参数必须 和父类方法完全一致
//        ✔ 访问权限不能比父类更严格（父类 public，子类不能 private）
//        ✔ 需加 @Override 注解（可选，但推荐）

        System.out.println("这是dog重写后eat方法");
    }

    @Override
    public void makeSound() {
        System.out.println("Dog barks.");
    }

}
// 多态子类
class Cat extends Animal{
    public Cat(String name){
        // 调用父类构造方法
        super(name);
    }

    @Override
    public void makeSound() {
        System.out.println("Cat barks.");
    }
}

// 抽象类
// 抽象类不能实例化，子类必须实现里面的抽象方法，可以有普通方法
abstract class Vehicle{

    // 定义一个抽象方法，子类必须实现
    abstract void display();

    // 具体方法，子类可以直接继承
    public void testfunc(){
        System.out.println("抽象具体方法");
    }
}

class Vechicle1 extends Vehicle{
    public void display(){
        System.out.println("Vechicle1类实现display");
    }

    @Override
    public void testfunc(){
        System.out.println("重写抽象具体方法");
    }
}

class Vechicle2 extends Vehicle{
    public void display(){
        System.out.println("Vechicle2类实现display");
    }
}

// 接口
// 定义行为标准，不同类可以实现相同接口。
// 支持多继承（Java 不能多继承类，但可以实现多个接口）。
// ✔ 只能定义方法（不能有实例变量）
// ✔ 类用 implements 关键字实现接口
interface testInter{
    void display();// 定义方法
}

interface testInterTo{
    void success();
}

class testInter1 implements testInter,testInterTo{

    public void display(){
        System.out.println("testInter1子类实现接口方法display");
    }

    public void success(){
        System.out.println("testInter1子类实现接口方法success");
    }

}
</code></pre>]]></description>
    <pubDate>Tue, 01 Apr 2025 17:03:00 +0800</pubDate>
    <dc:creator>杨佳乐</dc:creator>
    <guid>https://www.itjiale.com/post/89</guid>
</item>
<item>
    <title>java 基础数据类型</title>
    <link>https://www.itjiale.com/post/88</link>
    <description><![CDATA[<pre><code class="language-java">public class Demo2 {

    public static void main(String[] args) {

        System.out.println("Hello Word Java!");

        // 变量类型和数据
        int age = 25;//整数
        double price = 19.11;//小数
        char grade = 'A';//单个字符
        boolean isJavaFun = true;
        String name = "test";//字符串

        int a = 1,b = 2;

        // 算术运算符
        System.out.println(a + b);
        System.out.println(a - b);
        System.out.println(a * b);
        System.out.println(a / b);
        System.out.println(a % b);

        // 关系运算符
        System.out.println(a == b);
        System.out.println(a != b);
        System.out.println(a &gt; b);
        System.out.println(a &lt; b);

        // 逻辑运算符
        boolean x = true,y = false;
        System.out.println(x &amp;&amp; y);// false
        System.out.println(x || y);// true
        System.out.println(!x);// false

        // 流程控制
        int score = 85;
        if (score &gt;= 90){
            System.out.println("&gt;90 优秀");
        }else if (score &gt;= 60){
            System.out.println("&gt;60 及格");
        }else {
            System.out.println("不及格");
        }

        int day = 2;
        switch (day){
            case 1:
                System.out.println("day = 1");
                break;
            case 2:
                System.out.println("day = 2");
                break;
            case 3:
                System.out.println("day = 3");
                break;
            default:
                System.out.println("day != 1 &amp;&amp; day !=2 &amp;&amp; day !=3");
                break;
        }

        // for循环
        for (int i = 0;i &lt; 10;i++){
            System.out.println("for:"+i);
        }

        // while循环
        int i = 0;
        while (i &lt; 5){
            System.out.println("while:"+i);
            i++;
        }

        // do while循环(先执行循环体，在判断条件)
        int i2 = 5;
        do {
            System.out.println("do while i2:"+i2);
        }while (i2 &lt; 5);

        // 数组
        int[] numbers = {1,2,3,4,5};

        for (int number : numbers){
            System.out.println("循环数组:"+number);
        }

        // 调用方法
        sayHello();

        int res = add(1,5);

        System.out.println("结果是:"+res);

        // new class
        Person person1 = new Person("test1",25);

        // 调用对象方法
        person1.sayHello();

        // 调用静态方法
        Person.testStatic();

        Person.pubStatic();

    }

    // 方法
    public static void sayHello(){
        System.out.println("这是sayHello()方法");
    }

    // add方法
    public static int add(int a,int b){
        System.out.println("a:"+a+" + b:"+b+" = "+ (a + b));
        return a + b;
    }

}

// 类与对象
class Person{

//    特性    public 方法   static 方法   public static 方法
//    调用方式  需要对象实例  通过类名调用  通过类名调用
//    访问实例成员    可以直接访问  不能直接访问  不能直接访问
//    访问静态成员    可以访问    可以访问    可以访问
//    内存分配  对象创建时分配 类加载时分配  类加载时分配
//    使用场景  对象特有的行为 工具方法/类级别操作  公共工具方法
//    多态支持  支持方法重写  不支持重写   不支持重写

    String name;
    int age;
    static int test1 = 20;

    // 构造方法
    Person(String name,int age){
        this.name = name;
        this.age = age;
    }

    // 普通方法
    void sayHello(){
        System.out.println("Hello,my name is "+ name);
    }

    // 静态方法
    static void testStatic(){
        System.out.println("这是静态方法,test1变量:"+test1);
    }

    // 公共静态方法
    public static void pubStatic(){
        System.out.println("这是public静态方法,test1变量:"+test1);
    }

}
</code></pre>]]></description>
    <pubDate>Tue, 01 Apr 2025 09:12:00 +0800</pubDate>
    <dc:creator>杨佳乐</dc:creator>
    <guid>https://www.itjiale.com/post/88</guid>
</item>
<item>
    <title>Flex 布局</title>
    <link>https://www.itjiale.com/post/87</link>
    <description><![CDATA[<p>一、Flex 布局是什么？<br />
Flex 是 Flexible Box 的缩写，意为&quot;弹性布局&quot;，用来为盒状模型提供最大的灵活性。</p>
<p>任何一个容器都可以指定为 Flex 布局。</p>
<pre><code class="language-html">.box{
  display: flex;
}</code></pre>
<p>行内元素也可以使用 Flex 布局。</p>
<pre><code class="language-html">.box{
  display: inline-flex;
}</code></pre>
<p>Webkit 内核的浏览器，必须加上-webkit前缀。</p>
<pre><code class="language-html">.box{
  display: -webkit-flex; /* Safari */
  display: flex;
}</code></pre>
<p>注意，设为 Flex 布局以后，子元素的float、clear和vertical-align属性将失效。</p>
<p>二、基本概念<br />
采用 Flex 布局的元素，称为 Flex 容器（flex container），简称&quot;容器&quot;。它的所有子元素自动成为容器成员，称为 Flex 项目（flex item），简称&quot;项目&quot;。<br />
<a href="https://www.itjiale.com/content/uploadfile/202503/db981743072034.png"><img src="https://www.itjiale.com/content/uploadfile/202503/db981743072034.png" alt="" /></a></p>
<p>容器默认存在两根轴：水平的主轴（main axis）和垂直的交叉轴（cross axis）。主轴的开始位置（与边框的交叉点）叫做main start，结束位置叫做main end；交叉轴的开始位置叫做cross start，结束位置叫做cross end。<br />
项目默认沿主轴排列。单个项目占据的主轴空间叫做main size，占据的交叉轴空间叫做cross size。</p>
<p>三、容器的属性<br />
以下6个属性设置在容器上。</p>
<p>flex-direction<br />
flex-wrap<br />
flex-flow<br />
justify-content<br />
align-items<br />
align-content</p>
<p>flex-direction属性<br />
flex-direction属性决定主轴的方向（即项目的排列方向）。</p>
<pre><code class="language-html">.box {
  flex-direction: row | row-reverse | column | column-reverse;
}</code></pre>
<p><a href="https://www.itjiale.com/content/uploadfile/202503/76e41743072132.png"><img src="https://www.itjiale.com/content/uploadfile/202503/76e41743072132.png" alt="" /></a></p>
<p>它可能有4个值。<br />
row（默认值）：主轴为水平方向，起点在左端。<br />
row-reverse：主轴为水平方向，起点在右端。<br />
column：主轴为垂直方向，起点在上沿。<br />
column-reverse：主轴为垂直方向，起点在下沿。</p>
<p>flex-wrap属性<br />
默认情况下，项目都排在一条线（又称&quot;轴线&quot;）上。flex-wrap属性定义，如果一条轴线排不下，如何换行。<a href="https://www.itjiale.com/content/uploadfile/202503/eb0a1743072202.png"><img src="https://www.itjiale.com/content/uploadfile/202503/eb0a1743072202.png" alt="" /></a></p>
<pre><code class="language-html">.box{
  flex-wrap: nowrap | wrap | wrap-reverse;
}</code></pre>
<p>它可能取三个值。</p>
<p>（1）nowrap（默认）：不换行。<br />
<a href="https://www.itjiale.com/content/uploadfile/202503/68601743072238.png"><img src="https://www.itjiale.com/content/uploadfile/202503/68601743072238.png" alt="" /></a><br />
（2）wrap：换行，第一行在上方。<br />
<a href="https://www.itjiale.com/content/uploadfile/202503/18a11743072276.png"><img src="https://www.itjiale.com/content/uploadfile/202503/18a11743072276.png" alt="" /></a><br />
（3）wrap-reverse：换行，第一行在下方。<br />
<a href="https://www.itjiale.com/content/uploadfile/202503/516d1743072285.png"><img src="https://www.itjiale.com/content/uploadfile/202503/516d1743072285.png" alt="" /></a></p>
<p>flex-flow<br />
flex-flow属性是flex-direction属性和flex-wrap属性的简写形式，默认值为row nowrap。</p>
<pre><code class="language-html">.box {
  flex-flow: &lt;flex-direction&gt; || &lt;flex-wrap&gt;;
}</code></pre>
<p>justify-content属性<br />
justify-content属性定义了项目在主轴上的对齐方式。</p>
<pre><code class="language-html">.box {
  justify-content: flex-start | flex-end | center | space-between | space-around;
}</code></pre>
<p><a href="https://www.itjiale.com/content/uploadfile/202503/b3e31743072361.png"><img src="https://www.itjiale.com/content/uploadfile/202503/b3e31743072361.png" alt="" /></a><br />
它可能取5个值，具体对齐方式与轴的方向有关。下面假设主轴为从左到右。</p>
<p>flex-start（默认值）：左对齐<br />
flex-end：右对齐<br />
center： 居中<br />
space-between：两端对齐，项目之间的间隔都相等。<br />
space-around：每个项目两侧的间隔相等。所以，项目之间的间隔比项目与边框的间隔大一倍。</p>
<p>align-items属性<br />
align-items属性定义项目在交叉轴上如何对齐。<br />
<a href="https://www.itjiale.com/content/uploadfile/202503/0c211743072434.png"><img src="https://www.itjiale.com/content/uploadfile/202503/0c211743072434.png" alt="" /></a><br />
它可能取5个值。具体的对齐方式与交叉轴的方向有关，下面假设交叉轴从上到下。</p>
<p>flex-start：交叉轴的起点对齐。<br />
flex-end：交叉轴的终点对齐。<br />
center：交叉轴的中点对齐。<br />
baseline: 项目的第一行文字的基线对齐。<br />
stretch（默认值）：如果项目未设置高度或设为auto，将占满整个容器的高度。</p>
<p>align-content属性<br />
align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线，该属性不起作用。</p>
<pre><code class="language-html">.box {
  align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}</code></pre>
<p><a href="https://www.itjiale.com/content/uploadfile/202503/61a71743072543.png"><img src="https://www.itjiale.com/content/uploadfile/202503/61a71743072543.png" alt="" /></a><br />
该属性可能取6个值。</p>
<p>flex-start：与交叉轴的起点对齐。<br />
flex-end：与交叉轴的终点对齐。<br />
center：与交叉轴的中点对齐。<br />
space-between：与交叉轴两端对齐，轴线之间的间隔平均分布。<br />
space-around：每根轴线两侧的间隔都相等。所以，轴线之间的间隔比轴线与边框的间隔大一倍。<br />
stretch（默认值）：轴线占满整个交叉轴。</p>
<p>项目的属性<br />
以下6个属性设置在项目上。</p>
<p>order<br />
flex-grow<br />
flex-shrink<br />
flex-basis<br />
flex<br />
align-self</p>
<p>order属性<br />
order属性定义项目的排列顺序。数值越小，排列越靠前，默认为0。</p>
<pre><code class="language-html">.item {
  order: &lt;integer&gt;;
}</code></pre>
<p><a href="https://www.itjiale.com/content/uploadfile/202503/62281743072605.png"><img src="https://www.itjiale.com/content/uploadfile/202503/62281743072605.png" alt="" /></a></p>
<p>flex-grow属性<br />
flex-grow属性定义项目的放大比例，默认为0，即如果存在剩余空间，也不放大。</p>
<pre><code class="language-html">.item {
  flex-grow: &lt;number&gt;; /* default 0 */
}</code></pre>
<p><a href="https://www.itjiale.com/content/uploadfile/202503/6f061743072639.png"><img src="https://www.itjiale.com/content/uploadfile/202503/6f061743072639.png" alt="" /></a><br />
如果所有项目的flex-grow属性都为1，则它们将等分剩余空间（如果有的话）。如果一个项目的flex-grow属性为2，其他项目都为1，则前者占据的剩余空间将比其他项多一倍。</p>
<p>flex-shrink属性<br />
flex-shrink属性定义了项目的缩小比例，默认为1，即如果空间不足，该项目将缩小。</p>
<pre><code class="language-html">.item {
  flex-shrink: &lt;number&gt;; /* default 1 */
}</code></pre>
<p><a href="https://www.itjiale.com/content/uploadfile/202503/d7381743072679.png"><img src="https://www.itjiale.com/content/uploadfile/202503/d7381743072679.png" alt="" /></a></p>
<p>如果所有项目的flex-shrink属性都为1，当空间不足时，都将等比例缩小。如果一个项目的flex-shrink属性为0，其他项目都为1，则空间不足时，前者不缩小。<br />
负值对该属性无效。</p>
<p>flex-basis属性<br />
flex-basis属性定义了在分配多余空间之前，项目占据的主轴空间（main size）。浏览器根据这个属性，计算主轴是否有多余空间。它的默认值为auto，即项目的本来大小。</p>
<pre><code class="language-html">.item {
  flex-basis: &lt;length&gt; | auto; /* default auto */
}</code></pre>
<p>它可以设为跟width或height属性一样的值（比如350px），则项目将占据固定空间。</p>
<p>flex属性<br />
flex属性是flex-grow, flex-shrink 和 flex-basis的简写，默认值为0 1 auto。后两个属性可选。</p>
<pre><code class="language-html">.item {
  flex: none | [ &lt;'flex-grow'&gt; &lt;'flex-shrink'&gt;? || &lt;'flex-basis'&gt; ]
}</code></pre>
<p>该属性有两个快捷值：auto (1 1 auto) 和 none (0 0 auto)。</p>
<p>建议优先使用这个属性，而不是单独写三个分离的属性，因为浏览器会推算相关值。</p>
<p>align-self属性<br />
align-self属性允许单个项目有与其他项目不一样的对齐方式，可覆盖align-items属性。默认值为auto，表示继承父元素的align-items属性，如果没有父元素，则等同于stretch。</p>
<pre><code class="language-html">.item {
  align-self: auto | flex-start | flex-end | center | baseline | stretch;
}</code></pre>
<p><a href="https://www.itjiale.com/content/uploadfile/202503/0acb1743072817.png"><img src="https://www.itjiale.com/content/uploadfile/202503/0acb1743072817.png" alt="" /></a></p>
<p>该属性可能取6个值，除了auto，其他都与align-items属性完全一致。</p>]]></description>
    <pubDate>Thu, 27 Mar 2025 18:38:00 +0800</pubDate>
    <dc:creator>杨佳乐</dc:creator>
    <guid>https://www.itjiale.com/post/87</guid>
</item>
<item>
    <title>使用php对接阿里云mps对oss上视频进行转码m3u8</title>
    <link>https://www.itjiale.com/post/86</link>
    <description><![CDATA[<p>目前许多短视频平台都采用把用户上传视频统一转码为m3u8+ts文件格式</p>
<p>主要优势：<br />
适应性流媒体传输：M3U8可以根据用户的网络速度自动调整视频质量，确保流畅播放。它通过提供不同质量级别的媒体文件链接，使播放器能够根据当前网络条件选择最合适的质量级别进行播放。</p>
<p>分段传输：将长视频分割成小片段，便于通过HTTP协议快速传输。这种方式使得视频可以边下载边播放，减少了等待时间。</p>
<p>跨平台兼容性：M3U8格式被广泛支持，可以在多种设备和浏览器上播放，包括移动设备、桌面计算机以及智能电视等。</p>
<p>直播和点播：M3U8既可以用于直播流媒体，也可以用于点播服务，使其成为在线视频平台的理想选择。</p>
<p>本次使用php对接阿里云提供的mps服务，对视频进行转码</p>
<p>安装以下SDK</p>
<pre><code class="language-shell">composer install alibabacloud/sdk
composer install alibabacloud/mts-20140618</code></pre>
<p>下面代码为提交转码任务</p>
<pre><code class="language-php">&lt;?php
namespace app;

use AlibabaCloud\SDK\Mts\V20140618\Models\SubmitJobsRequest;
use AlibabaCloud\SDK\Mts\V20140618\Mts;
use Darabonba\OpenApi\Models\Config;

use AlibabaCloud\Tea\Tea;
use AlibabaCloud\Tea\Utils\Utils;

class LeCommon
{

    const accessKeyId = 'LT*******mHs';
    const accessKeySecret = 'rki********P3J';
    const regionId = 'cn-hangzhou'; //地域id

    const PipelineId = '457cf7********2d77'; //管道ID

    const ossLocation = 'oss-cn-hangzhou';

    const bucket  = 'sh*****-1'; //oss bucket名称

      //此处为阿里云内置模板，转换1920全高清为m3u8+ts格式
    const templateId = "S00000001-100040"; #转码模板ID，按需配置
    const oss_input_object  = "test_input.mp4"; //oss上面的路径
    const oss_output_object  = "output_test"; //输出后的oss路径

    public static function createClient(){
        $config = new Config([]);
        $config-&gt;accessKeyId = self::accessKeyId;
        $config-&gt;accessKeySecret = self::accessKeySecret;
        $config-&gt;regionId = self::regionId;
        $config-&gt;protocol = "HTTPS";
        $config-&gt;endpoint = 'mts.cn-hangzhou.aliyuncs.com';
        return new Mts($config);
    }

    public static function test(){

        $client = self::createClient();

        $request = new SubmitJobsRequest([
            "input" =&gt; json_encode(array(
                'Location' =&gt; self::ossLocation,
                'Bucket' =&gt; self::bucket,
                'Object' =&gt; urlencode(self::oss_input_object))
            ),
            "outputBucket" =&gt; self::bucket,
            "outputLocation" =&gt; self::ossLocation,
            "pipelineId" =&gt; self::PipelineId,
            "outputs" =&gt; self::outputs(),
        ]);

        $response = $client-&gt;submitJobs($request);
        //Console::log();

        var_dump($response);
        var_dump(Utils::toJSONString(Tea::merge($response-&gt;body)));
    }

    public static function outputs() {
        $output = array('OutputObject' =&gt; urlencode(self::oss_output_object));
        $output['TemplateId'] = self::templateId;
        $outputs = array($output);
        return json_encode($outputs);
    }

}</code></pre>]]></description>
    <pubDate>Wed, 19 Mar 2025 08:37:00 +0800</pubDate>
    <dc:creator>杨佳乐</dc:creator>
    <guid>https://www.itjiale.com/post/86</guid>
</item>
<item>
    <title>php+wkhtmltoimage 将html转成图片</title>
    <link>https://www.itjiale.com/post/84</link>
    <description><![CDATA[<p>1.安装wkhtmltopdf<br />
ubuntu 安装<br />
sudo apt-get install wkhtmltopdf<br />
centos 安装<br />
sudo yum install wkhtmltopdf</p>
<p>2.php中使用thinkphp-template模板组件</p>
<pre><code class="language-php">$res = ThinkPHP::render('mobile',['html'=&gt;$html]);

        $filename = runtime_path().'/html/'.time().mt_rand(1,999).'.html';
        file_put_contents($filename, $res);

        $tempHtmlFile = $filename;

        // 生成图像输出文件路径
        $outputImageFile = runtime_path().'/html/res.png';

        // 使用 wkhtmltoimage 命令行工具生成图像
        //quality 质量 1-100
        //width 宽度
        //-disable-smart-width 禁用宽度自动调整
        // --zoom 0.8 缩小分辨率
        $command = "wkhtmltoimage --width 700 --quality 75 --disable-smart-width $tempHtmlFile $outputImageFile";
        //exec($command);
        exec($command, $output, $status);
        if ($status == 0) {
            echo "生成成功！";
        } else {
            echo "生成失败！状态码: " . $status;
            print_r($output);  // 查看详细的错误输出
        }

        if (file_exists($tempHtmlFile)) {
            unlink($tempHtmlFile);  // 删除临时文件
            echo "临时文件已删除";
        } else {
            echo "临时文件不存在，无法删除";
        }</code></pre>]]></description>
    <pubDate>Fri, 28 Feb 2025 16:30:00 +0800</pubDate>
    <dc:creator>杨佳乐</dc:creator>
    <guid>https://www.itjiale.com/post/84</guid>
</item>
<item>
    <title>Java 特点</title>
    <link>https://www.itjiale.com/post/82</link>
    <description><![CDATA[<pre><code class="language-java">public class Demo1 {

    public static void main(String[] args) {
//        Java 特点

//        1. 平台独立性
//        解释：Java 是一次编写，处处运行。它通过 Java 虚拟机（JVM）来实现平台无关性，程序在任何平台上都可以运行，只要该平台上有 Java 环境。
//        原理：Java 源代码编译后会生成字节码文件（.class），然后 JVM 解释和执行这些字节码，不直接依赖于底层操作系统。
//        2. 面向对象
//        解释：Java 是一门面向对象的编程语言，几乎所有的内容都作为对象存在。面向对象有四个基本特性：
//        封装：数据和方法被封装在对象中，外界不能直接访问对象的属性，只能通过方法来操作对象的数据。
//        继承：Java 允许类之间的继承，子类可以继承父类的属性和方法，从而实现代码重用。
//        多态：多态允许通过父类引用指向子类对象，并在运行时决定调用哪个方法。这样可以使得代码更具扩展性。
//        抽象：抽象允许你只关心对象的行为而不关心其具体实现，通常通过抽象类或接口来实现。
//        3. 简洁和易学
//        解释：Java 的语法比较简洁，比 C++ 少了指针、手动内存管理等复杂特性，学习起来相对容易。
//        优点：对初学者来说，Java 提供了清晰且易于理解的结构和语法，快速上手。
//        4. 垃圾回收机制
//        解释：Java 有自动的垃圾回收机制，JVM 会自动管理内存，定期清理不再使用的对象，减少了内存泄漏的风险。
//        原理：通过垃圾回收（GC）机制，程序员不需要手动释放内存，只需关注逻辑和性能，JVM 会自动处理内存的分配和回收。
//        5. 多线程支持
//        解释：Java 提供了内建的多线程支持，可以轻松创建多线程应用。Java 提供了线程类和接口，使得线程的管理和同步变得容易。
//        原理：Java 通过 Thread 类和 Runnable 接口来创建和管理线程，使用 synchronized 关键字来保证线程之间的同步，避免数据竞争。
//        6. 丰富的标准库
//        解释：Java 提供了大量的标准类库，涵盖了输入输出、网络、数据库、GUI、并发等各种功能。
//        优点：你可以直接使用这些库来完成常见的开发任务，而不必自己从头编写。
//        7. 安全性
//        解释：Java 的安全性设计非常严密，能够有效避免很多常见的安全问题。通过 Java 安全管理器和字节码验证机制，Java 可以有效防止恶意代码的执行。
//        原理：Java 提供了一种安全的执行环境，可以限制应用程序对系统资源的访问，防止程序执行潜在的有害操作。
//        8. 跨平台性
//        解释：Java 程序通过 JVM 实现跨平台执行，Java 程序可以在不同操作系统上运行，如 Windows、Linux、macOS 等。
//        原理：只要目标操作系统上安装了相应的 JVM，就可以执行相同的字节码。
//        9. 高性能
//        解释：Java 是一种编译型语言，编译后的字节码执行速度较快，而且随着 JVM 和垃圾回收技术的优化，Java 性能也在不断提高。
//        优化：现代的 JIT（即时编译）技术可以将热点代码编译成本地机器码，从而提高执行效率。
//        10. 大规模应用支持
//        解释：Java 具有良好的扩展性，适合开发大规模的应用，广泛应用于企业级应用、Web 开发和大数据处理等领域。

    }
}
</code></pre>]]></description>
    <pubDate>Mon, 24 Feb 2025 22:07:00 +0800</pubDate>
    <dc:creator>杨佳乐</dc:creator>
    <guid>https://www.itjiale.com/post/82</guid>
</item>
<item>
    <title>Golang gorm demo2</title>
    <link>https://www.itjiale.com/post/81</link>
    <description><![CDATA[<pre><code class="language-go">package main

import (
    "fmt"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "gorm.io/gorm/schema"
    "time"
)

// 定义模型
type Admin struct {
    ID uint `gorm:"primaryKey;not null"`
    Username string `gorm:"size:100;not null"`
    Password string `gorm:"size:200;not null"`
    Nickname string `gorm:"size:100"`
    CreatedAt time.Time `gorm:"type:datetime"`
    UpdatedAt time.Time `gorm:"type:datetime"`
}

var DB *gorm.DB

func main(){

    dsn := "test:test@tcp(127.0.0.1:3306)/gormdemo1?charset=utf8mb4&amp;parseTime=True&amp;loc=Local"
    db, err := gorm.Open(mysql.Open(dsn), &amp;gorm.Config{
        NamingStrategy: schema.NamingStrategy{
            TablePrefix:   "la_", // 设置表前缀
            SingularTable: false,      // 禁用表名复数
        },
    })
    if err != nil {
        fmt.Println("数据库连接失败")
    }

    DB = db

    // 创建表
    DB.AutoMigrate(&amp;Admin{})

    // 添加数据
    admin1 := Admin{
        Username:"admin",
        Password:"pwd",
        Nickname:"nickadm",
    }

    DB.Create(&amp;admin1)

    if admin1.ID &gt; 0 {
        fmt.Println("创建成功")
    }

    var searchadm1 Admin

    DB.Find(&amp;searchadm1,3)

    fmt.Println(searchadm1)

    if searchadm1.ID &gt; 0 {
        DB.Delete(searchadm1)
    }

    fmt.Println("执行完成")

}</code></pre>]]></description>
    <pubDate>Fri, 17 Jan 2025 15:46:00 +0800</pubDate>
    <dc:creator>杨佳乐</dc:creator>
    <guid>https://www.itjiale.com/post/81</guid>
</item>
<item>
    <title>Golang gorm demo1</title>
    <link>https://www.itjiale.com/post/80</link>
    <description><![CDATA[<pre><code class="language-go">package main

import (
    "fmt"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "gorm.io/gorm/schema"
    "time"
)

// 定义用户模型
type User struct {
    ID uint `gorm:"primaryKey;not null"`
    Name string `gorm:"size:100"`
    Mobile string `gorm:"uniqueIndex;size:20"`
    CreatedAt time.Time
    UpdatedAt time.Time
}

func main(){

    dsn := "root:123456@tcp(127.0.0.1:3306)/gormdemo1?charset=utf8mb4&amp;parseTime=True&amp;loc=Local"
    db, err := gorm.Open(mysql.Open(dsn), &amp;gorm.Config{
        NamingStrategy: schema.NamingStrategy{
            TablePrefix:   "tes_", // 设置表前缀
            SingularTable: false,      // 禁用表名复数
        },
    })
    if err != nil {
        fmt.Println("数据库连接失败: %v", err)
    }

    fmt.Println("数据库连接成功!")

    err = db.AutoMigrate(&amp;User{})
    if err != nil {
        fmt.Println("创建User表失败: %v", err)
    }
    fmt.Println("创建User表成功")

    // 添加一条数据
    // user1 := User{
    //  Name:"user1",
    //  Mobile:"1000000000",
    // }

    // result := db.Create(&amp;user1)

    // if result.Error != nil {
    //  fmt.Println("failed to create user: %v", result.Error)
    // }

    // fmt.Println(user1)

    // 查询数据
    var user User

    // 主键查询
    db.Find(&amp;user,1)

    var user2 User

    // 条件查询
    db.Find(&amp;user2,"mobile = ?","1000000000")

    fmt.Println(user)
    fmt.Println(user2)

    // 模拟动态条件
    var wheres = make(map[string]interface{})
    wheres["name"] = "test"
    wheres["mobile"] = "111"
    // wheres := map[string]interface{}{"name":"test","mobile":"1111",}

    var user3 User
    query := db.Model(&amp;User{})
    for key,value := range wheres{

        if value != "" {
            query = query.Where(fmt.Sprintf("%s = ?", key), value)
        }
    }
    query.Find(&amp;user3)

    var upduser User
    db.Find(&amp;upduser,1)
    // 更新某个字段
    db.Model(&amp;upduser).Update("mobile","123123")

    // 更新多个字段
    db.Model(&amp;upduser).Updates(&amp;User{Name:"aaaa",Mobile:"1000000000"})

    // 删除
    db.Delete(&amp;upduser)

    // 查询多条数据
    var userlist []User
    db.Where("id &gt; ?",0).Find(&amp;userlist)
    fmt.Println(userlist)
    for k,v := range userlist {
        fmt.Println(k)
        fmt.Println(v.Name)
    }

    var orderlist []User
    // 分页及排序
    db.Order("id desc").Limit(10).Offset(0).Find(&amp;orderlist)

    fmt.Println(orderlist)

    // 事务操作
    err = db.Transaction(func(tx *gorm.DB) error {
        if err := tx.Create(&amp;User{Name: "User1",Mobile:"1700000111"}).Error; err != nil {
            return err
        }
        if err := tx.Create(&amp;User{Name: "User2",Mobile:"160000"}).Error; err != nil {
            return err
        }
        return nil
    })

    if err != nil {
        fmt.Println("出现事务错误")
        fmt.Println(err)
    }

    pageFind(db)

    // 关闭连接
    mysqldb,err := db.DB()

    mysqldb.Close()

}

// 分页查询，处理总数量、总页数
func pageFind(db *gorm.DB){

    fmt.Println("进入分页方法查询")

    var totalCount int64

    query := db.Model(&amp;User{}).Where("id &gt; 0")

    // 查询总数量
    query.Count(&amp;totalCount)

    // 查询当前页数据
    var list []User

    pageSize := 2
    currentPage := 0

    db.Limit(pageSize).Offset(currentPage).Find(&amp;list)

    // 计算总页数
    totalPages := (totalCount + int64(pageSize) - 1) / int64(pageSize)

    fmt.Println("分页查询完毕")
    fmt.Println(list)
    fmt.Println("总数量",totalCount,"总页数",totalPages)
}</code></pre>]]></description>
    <pubDate>Fri, 17 Jan 2025 13:51:00 +0800</pubDate>
    <dc:creator>杨佳乐</dc:creator>
    <guid>https://www.itjiale.com/post/80</guid>
</item>
<item>
    <title>Golang gorm包</title>
    <link>https://www.itjiale.com/post/79</link>
    <description><![CDATA[<pre><code class="language-go">package main

// gorm 官方文档
// https://gorm.io/zh_CN/docs/

// 安装gorm
// go get -u gorm.io/gorm
// go get -u gorm.io/driver/mysql

// 如果因网络问题无法安装，尝试更换网络源
// 设置清华大学源
// go env -w GOPROXY=https://goproxy.cn,direct

// 初始化数据库连接
// import (
//  "gorm.io/driver/mysql"
//  "gorm.io/gorm"
//  "log"
// )

// func main() {
//  dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&amp;parseTime=True&amp;loc=Local"
//  db, err := gorm.Open(mysql.Open(dsn), &amp;gorm.Config{})
//  if err != nil {
//      log.Fatalf("failed to connect database: %v", err)
//  }

//  log.Println("Database connected successfully!")
// }
// dsn：数据源名称，需要替换 user、password 和 dbname。
// gorm.Config{}：GORM 的配置选项。

// 定义模型
// 定义与数据库表对应的模型
// type User struct {
//  ID        uint   `gorm:"primaryKey"`
//  Name      string `gorm:"size:100"`
//  Email     string `gorm:"uniqueIndex;size:100"`
//  CreatedAt time.Time
//  UpdatedAt time.Time
//  DeletedAt gorm.DeletedAt `gorm:"index"`
// }

// 迁移表结构
// 使用 GORM 的自动迁移功能创建表
// err = db.AutoMigrate(&amp;User{})
// if err != nil {
//  log.Fatalf("failed to migrate database: %v", err)
// }
// log.Println("Database migrated successfully!")

// 基本操作
// 1.创建数据
// user := User{Name: "John Doe", Email: "john.doe@example.com"}
// result := db.Create(&amp;user)

// if result.Error != nil {
//  log.Fatalf("failed to create user: %v", result.Error)
// }

// log.Printf("User created successfully: %+v", user)

// 2.查询记录
// var user User
// db.First(&amp;user, 1) // 根据主键查询
// db.First(&amp;user, "email = ?", "john.doe@example.com") // 条件查询

// log.Printf("User found: %+v", user)

// 3.更新记录
// db.Model(&amp;user).Update("Name", "Jane Doe")
// db.Model(&amp;user).Updates(User{Name: "Jane Doe", Email: "jane.doe@example.com"}) // 批量更新

// 4.删除记录
// db.Delete(&amp;user) // 根据主键删除

// 高级功能
// 1.查询多条数据
// var users []User
// db.Where("name LIKE ?", "%Doe%").Find(&amp;users)
// log.Printf("Users found: %+v", users)

// 2.分页和排序
// var users []User
// db.Order("created_at desc").Limit(10).Offset(0).Find(&amp;users) // 分页

// 3.事务支持
// err = db.Transaction(func(tx *gorm.DB) error {
//  if err := tx.Create(&amp;User{Name: "User1"}).Error; err != nil {
//      return err
//  }
//  if err := tx.Create(&amp;User{Name: "User2"}).Error; err != nil {
//      return err
//  }
//  return nil
// })
// if err != nil {
//  log.Fatalf("Transaction failed: %v", err)
// }

// 常用配置
// 在初始化时配置 GORM 的行为
// db, err := gorm.Open(mysql.Open(dsn), &amp;gorm.Config{
//  Logger: logger.Default.LogMode(logger.Info), // 显示详细的 SQL 日志
// })

// 字段级权限控制
// type User struct {
//  Name string `gorm:"&lt;-:create"` // 允许读和创建
//  Name string `gorm:"&lt;-:update"` // 允许读和更新
//  Name string `gorm:"&lt;-"`        // 允许读和写（创建和更新）
//  Name string `gorm:"&lt;-:false"`  // 允许读，禁止写
//  Name string `gorm:"-&gt;"`        // 只读（除非有自定义配置，否则禁止写）
//  Name string `gorm:"-&gt;;&lt;-:create"` // 允许读和写
//  Name string `gorm:"-&gt;:false;&lt;-:create"` // 仅创建（禁止从 db 读）
//  Name string `gorm:"-"`  // 通过 struct 读写会忽略该字段
//  Name string `gorm:"-:all"`        // 通过 struct 读写、迁移会忽略该字段
//  Name string `gorm:"-:migration"`  // 通过 struct 迁移会忽略该字段
//   }

// 创建/更新时间追踪（纳秒、毫秒、秒、Time）
// GORM 约定使用 CreatedAt、UpdatedAt 追踪创建/更新时间。如果您定义了这种字段，GORM 在创建、更新时会自动填充 当前时间
// 要使用不同名称的字段，您可以配置 autoCreateTime、autoUpdateTime 标签。
// 如果您想要保存 UNIX（毫/纳）秒时间戳，而不是 time，您只需简单地将 time.Time 修改为 int 即可
// type User struct {
//  CreatedAt time.Time // 在创建时，如果该字段值为零值，则使用当前时间填充
//  UpdatedAt int       // 在创建时该字段值为零值或者在更新时，使用当前时间戳秒数填充
//  Updated   int64 `gorm:"autoUpdateTime:nano"` // 使用时间戳纳秒数填充更新时间
//  Updated   int64 `gorm:"autoUpdateTime:milli"` // 使用时间戳毫秒数填充更新时间
//  Created   int64 `gorm:"autoCreateTime"`      // 使用时间戳秒数填充创建时间
//   }

//字段标签
// column   指定 db 列名
// type 列数据类型，推荐使用兼容性好的通用类型，例如：所有数据库都支持 bool、int、uint、float、string、time、bytes 并且可以和其他标签一起使用，例如：not null、size, autoIncrement… 像 varbinary(8) 这样指定数据库数据类型也是支持的。在使用指定数据库数据类型时，它需要是完整的数据库数据类型，如：MEDIUMINT UNSIGNED not NULL AUTO_INCREMENT
// serializer   指定将数据序列化或反序列化到数据库中的序列化器, 例如: serializer:json/gob/unixtime
// size 定义列数据类型的大小或长度，例如 size: 256
// primaryKey   将列定义为主键
// unique   将列定义为唯一键
// default  定义列的默认值
// precision    指定列的精度
// scale    指定列大小
// not null 指定列为 NOT NULL
// autoIncrement    指定列为自动增长
// autoIncrementIncrement   自动步长，控制连续记录之间的间隔
// embedded 嵌套字段
// embeddedPrefix   嵌入字段的列名前缀
// autoCreateTime   创建时追踪当前时间，对于 int 字段，它会追踪时间戳秒数，您可以使用 nano/milli 来追踪纳秒、毫秒时间戳，例如：autoCreateTime:nano
// autoUpdateTime   创建/更新时追踪当前时间，对于 int 字段，它会追踪时间戳秒数，您可以使用 nano/milli 来追踪纳秒、毫秒时间戳，例如：autoUpdateTime:milli
// index    根据参数创建索引，多个字段使用相同的名称则创建复合索引，查看 索引 获取详情
// uniqueIndex  与 index 相同，但创建的是唯一索引
// check    创建检查约束，例如 check:age &gt; 13，查看 约束 获取详情
// &lt;-   设置字段写入的权限， &lt;-:create 只创建、&lt;-:update 只更新、&lt;-:false 无写入权限、&lt;- 创建和更新权限
// -&gt;   设置字段读的权限，-&gt;:false 无读权限
// -    忽略该字段，- 表示无读写，-:migration 表示无迁移权限，-:all 表示无读写迁移权限
// comment  迁移时为字段添加注释

// 配置表前缀
// dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&amp;parseTime=True&amp;loc=Local"
// db, err := gorm.Open(mysql.Open(dsn), &amp;gorm.Config{
//  NamingStrategy: schema.NamingStrategy{
//      TablePrefix:   "prefix_", // 设置表前缀
//      SingularTable: true,      // 禁用表名复数
//  },
//  Logger: logger.Default.LogMode(logger.Info),
// })
// TablePrefix：设置表前缀，例如 prefix_。
// SingularTable：
// 默认情况下，GORM 会将模型名转换为复数形式（如 User -&gt; users）。
// 设置为 true 后，表名将保持单数形式。

// 自定义表名
// 对某个模型单独设置表名，可以实现 TableName 方法
// type User struct {
//     ID   uint
//     Name string
// }

// func (User) TableName() string {
//     return "custom_user_table"
// }

// 其他常见配置
// sqlDB, _ := db.DB()
// sqlDB.SetMaxIdleConns(10) // 设置空闲连接数
// sqlDB.SetMaxOpenConns(100) // 设置最大连接数
// sqlDB.SetConnMaxLifetime(time.Hour) // 设置连接的最大生命周期

// 配置日志输出
// 可以定制 GORM 的日志行为，例如输出到文件

// file, _ := os.Create("gorm.log")
// newLogger := logger.New(
//     log.New(file, "\r\n", log.LstdFlags),
//     logger.Config{
//         SlowThreshold: time.Second,   // 慢查询阈值
//         LogLevel:      logger.Warn,   // 日志级别
//         IgnoreRecordNotFoundError: true,
//     },
// )

// db, err := gorm.Open(mysql.Open(dsn), &amp;gorm.Config{
//     Logger: newLogger,
// })

// 完整配置总结
    // dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&amp;parseTime=True&amp;loc=Local"
    // db, err := gorm.Open(mysql.Open(dsn), &amp;gorm.Config{
    //  SkipDefaultTransaction: true, // 跳过默认事务
    //  NamingStrategy: schema.NamingStrategy{
    //      TablePrefix:   "prefix_", // 设置表前缀
    //      SingularTable: true,      // 禁用表名复数
    //  },
    //  Logger: logger.Default.LogMode(logger.Info), // 显示详细日志
    // })

    // if err != nil {
    //  log.Fatalf("failed to connect database: %v", err)
    // }

    // // 配置连接池
    // sqlDB, _ := db.DB()
    // sqlDB.SetMaxIdleConns(10)
    // sqlDB.SetMaxOpenConns(100)
    // sqlDB.SetConnMaxLifetime(time.Hour)

    // log.Println("Database connected successfully!")

func main(){

}</code></pre>]]></description>
    <pubDate>Fri, 17 Jan 2025 10:49:00 +0800</pubDate>
    <dc:creator>杨佳乐</dc:creator>
    <guid>https://www.itjiale.com/post/79</guid>
</item></channel>
</rss>