月份:2018年8月

Springboot之Hibernate自动建表

1、引入Maven依赖包

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

2、修改配置文件  application.properties

spring.profiles.active=dev
###############################
#数据库用户名
spring.datasource.username=root
#数据库密码
spring.datasource.password=admin
#数据库驱动
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#数据库连接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/study?useUnicode=true&characterEncoding=UTF-8&&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull
#JPA Configuration:
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.hbm2ddl.auto=update

3、创建实体类

UserInfo.java

package com.wjy329.studyshiro.entity;

import java.io.Serializable;
import java.util.List;
import javax.persistence.*;

/**
 * @author wjy329
 * @date 2018/8/23
 * @description ${description}
 */
@Entity
@Table(name = "user_info")
public class UserInfo implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id@GeneratedValue
    private long uid;//用户id;
    @Column(unique=true)
    private String username;//账号.
    private String name;//名称(昵称或者真实姓名,不同系统不同定义)
    private String password; //密码;
    private String salt;//加密密码的盐
    private byte state;//用户状态,0:创建未认证(比如没有激活,没有输入验证码等等)--等待验证的用户 , 1:正常状态,2:用户被锁定.
    private List<SysRole> roleList;// 一个用户具有多个角色
    public List<SysRole> getRoleList() {
        return roleList;
    }

    public void setRoleList(List<SysRole> roleList) {
        this.roleList = roleList;
    }

    public long getUid() {
        return uid;
    }

    public void setUid(long uid) {
        this.uid = uid;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getName() {
        return name;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getSalt() {
        return salt;
    }

    public void setSalt(String salt) {
        this.salt = salt;
    }

    public byte getState() {
        return state;
    }

    public void setState(byte state) {
        this.state = state;
    }

    /**
     * 密码盐.
     * @return
     */
    public String getCredentialsSalt(){
        return this.username+this.salt;
    }

    @Override
    public String toString() {
        return "UserInfo [uid=" + uid + ", username=" + username + ", name=" + name + ", password=" + password
                + ", salt=" + salt + ", state=" + state + "]";
    }
}

注意注解的添加: @Entity @Table @Id @GeneratedValue

最后运行启动类即可,就会在数据库中生成相应的表。

图片.png

Java学习之线程池(二)-Executor框架

1、Executor框架的结构

Executor框架由三部分组成:

  • 任务

  • 任务的执行

  • 异步计算的结果

步骤: 

1、主线程首先要创建实现Runnable或者Callable接口的任务对象。工具类Executors可以把一个Runnable对象封装为一个Callable对象或Executors.callable

2、然后可以把Runnable对象直接交给ExecutorService执行;

3、最后,主线程可以执行FutureTask.get()方法来等待任务执行完成。

2、Executor框架的成员

ThreadPoolExecutor、ScheduledThreadPoolExecutor、Future接口、Runnable接口、Callable接口和Executors;

(1)ThreadPoolExecutor 通常使用工厂类Executors来创建。Executors可以创建3种类型的ThreadPoolExecutor:

    SingleThreadExecutor、FixedThreadPool和CachedThreadPool

  •     FixedThreadPool   创建使用固定线程数的线程池;适用于为了满足资源管理的需求,而需要限制当前线程数量的应用场景,适用于负载比较重的服务器。

  •     SingleThreadExecutor  创建使用单个线程的线程池;适用于需要保证顺序地执行各个任务;并且在任意时间点,不会有多个线程是活动的应用场景。

  •     CachedThreadPool  创建一个会根据需要创建新线程的线程池;适用于执行很多的短期异步任务的小程序。

(2)ScheduledThreadPoolExecutor 通常使用工厂类Executors来创建。可以创建两种类型的ScheduledThreadPoolExecutor:

  •     ScheduledThreadPoolExecutor 包含若干个线程;适用于需要多个后台线程执行周期任务,同时为了满足资源管理的需求而需要限制后台线程的数量的应用场景。

  •    SingleScheduledThreadPoolExecutor 只包含一个线程;适用于需要单个后台线程执行周期任务,同时需要保证顺序的执行各个任务的应用场景。

   

Java学习之线程池(一)

最近的项目中使用了多线程,是直接new Thread(),发现总会有数据丢失的情况,感觉上是线程太多导致一些线程没抢到资源起不来。先用线程池实现多线程的运行,看看是否是多线程的问题。在这里记录下线程池的使用。

1、线程池的优点

  • 降低资源消耗

  • 提高响应速度

  • 提高线程的可管理性

2、线程池处理流程

(1)线程池判断核心线程池里的线程是否都在执行任务。如果不是,则创建一个新的工作线程来执行任务。如果核心线程池里的线程都在执行任务,则进入下个流程。

(2)线程池判断工作队列是否已经满。如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。

(3)线程池判断线程池的线程是否都处于工作状态。如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。

3、ThreadPoolExecutor 的使用

//创建线程池
private ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10,15, 3,
 TimeUnit. SECONDS, new ArrayBlockingQueue<Runnable>(3),
 new ThreadPoolExecutor.DiscardOldestPolicy());
 
 <!--private ThreadPoolExecutor threadPool = new ThreadPoolExecutor(int corePoolSize,
 int maximumPoolSize, long keepAliveTime,TimeUnit unit, 
 BlockingQueue<Runnable> paramBlockingQueue,
 RejectedExecutionHandler handler);  -->

//执行线程
Thread t = new Thread();
threadPool.execute(t);

如上面代码所示,线程池的使用其实很简单,就是搞清楚这几个参数是干嘛的就可以了。

corePoolSize:线程池核心线程数量

maximumPoolSize:线程池最大线程数量 (>=corePoolSize

keepAliveTime:当活跃线程数大于核心线程数时,空闲的多余线程最大存活时间

unit:存活时间的单位

paramBlockingQueue:存放任务的队列

handler:超出线程范围和队列容量的任务的处理程序

paramBlockingQueue类型选择

1)有界任务队列ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须指定大小;

2)无界任务队列LinkedBlockingQueue:基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE;

3)直接提交队列synchronousQueue:这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务。

handler策略:

AbortPolicy:丢弃任务并抛出RejectedExecutionException

CallerRunsPolicy:只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务。显然这样做不会真的丢弃任务,但是,任务提交线程的性能极有可能会急剧下降。

DiscardOldestPolicy:丢弃队列中最老的一个请求,也就是即将被执行的一个任务,并尝试再次提交当前任务。

DiscardPolicy:丢弃任务,不做任何处理。

后续将写java常用的四种线程池。

参考:https://www.cnblogs.com/superfj/p/7544971.html

        《Java并发编程的艺术》


Java学习之Serializable接口

我们在实体类的定义过程中,经常会用到Serialiazable接口,发现实现了该接口后,并没有实现该接口中的任何方法,那么这个接口的作用是干嘛的呢?

实现serializable接口的作用是就是实现序列化,可以把对象存到字节流,然后可以将字节流恢复为对象。

序列化后,字节流中包含了对象的信息,没有序列化将不能输出到字节流,无法保存对象信息。

下面我们演示一个实例:

先定义一个实体类并实现Serializable接口:

1、Person.java

package entity;

import java.io.Serializable;

/**
 * @Author: wjy329
 * @Time: 2018/8/18上午8:26
 */


public class Person implements Serializable{

    String name;
    int age;
    private static final long serialVersionUID = 1L;

    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }
    public String toString(){
        return "name:"+name+"\tage:"+age;
    }


}

2、写出对象信息

用ObjectOutputStream的writeObject()方法把这个类的对象写到文件,再通过ObjectInputStream的readObject()方法把这个对象读出来。

import entity.Person;

import java.io.*;

/**
 * @Author: wjy329
 * @Time: 2018/8/18上午8:25
 */

public class StudySerializable {
    public static void main(String[] args) {
        //初始化一个实体
        Person person = new Person("wjy",24);
        System.out.println(person);
        File file = new File("/Users/wjy329/desktop/out.txt");
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(file);
            ObjectOutputStream oos = null;
            try {
                oos = new ObjectOutputStream(fos);
                oos.writeObject(person);
                oos.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }finally{
                try {
                    oos.close();
                } catch (IOException e) {
                    System.out.println("oos关闭失败:"+e.getMessage());
                }
            }
        } catch (FileNotFoundException e) {
            System.out.println("找不到文件:"+e.getMessage());
        } finally{
            try {
                fos.close();
            } catch (IOException e) {
                System.out.println("fos关闭失败:"+e.getMessage());
            }
        }

        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            ObjectInputStream ois = null;
            try {
                ois = new ObjectInputStream(fis);
                try {
                    Person person1 = (Person)ois.readObject();
                    System.out.println(person1);
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }finally{
                try {
                    ois.close();
                } catch (IOException e) {
                    System.out.println("ois关闭失败:"+e.getMessage());
                }
            }
        } catch (FileNotFoundException e) {
            System.out.println("找不到文件:"+e.getMessage());
        } finally{
            try {
                fis.close();
            } catch (IOException e) {
                System.out.println("fis关闭失败:"+e.getMessage());
            }
        }
    }
}

运行代码后,控制台输出:

image.png

第一行打印的是初始化对象的信息,第二行是读取对象的信息。

将对象初始化后,然后输出到文件

image.png

然后在其他程序中只要是相同的对象并且对象中声明的serialVersionUID相同即可以将该文件中的信息转换为对象。

3、serialVersionUID

这个可以理解为序列化的id,只有id相同才代表是相同的对象,比如定义两个Person.java,即使其它属性相同,serialVersionUID不同也不能将对象信息读取出来。一般情况下默认值为1L,我们可以定义为其它的Long型值。


Java多线程学习(二)之卖票例子

多个窗口同时卖票,要保证不能卖出同一张票,即一个座位不能卖给多个人。

 1、继承Thread

/**
 * @Author: wjy329
 * @Time: 2018/8/16下午9:44
 */

public class TicketDemo {
    public static void main(String[] args) {
        Ticket t1 = new Ticket();
        Ticket t2 = new Ticket();
        Ticket t3 = new Ticket();
        Ticket t4 = new Ticket();

        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

class Ticket extends Thread{
    //初始化票数
    private int tick = 100;
    @Override
    public void run() {
        while (true){
            if(tick > 0){
                System.out.println(currentThread().getName()+"--已售出:"+tick--);
            }
        }
    }
}

此时运行结果:

image.png

会发现多个线程售出了同一张票。

我们只需在定义票数时设置为静态即可。

private static int tick =100;

/**
 * @Author: wjy329
 * @Time: 2018/8/16下午9:44
 */
public class TicketDemo {
    public static void main(String[] args) {
        Ticket t1 = new Ticket();
        Ticket t2 = new Ticket();
        Ticket t3 = new Ticket();
        Ticket t4 = new Ticket();

        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

class Ticket extends Thread{
    //初始化票数
    private static int tick = 100;
    @Override
    public void run() {
        while (true){
            if(tick > 0){
                System.out.println(currentThread().getName()+"--已售出:"+tick--);
            }
        }
    }
}

此时运行结果:

image.png

多个线程将100张票都卖完。

一般情况下,我们不定义静态,静态的生命周期较长;这时,换用下面的方法

/**
 * @Author: wjy329
 * @Time: 2018/8/16下午9:44
 */
public class TicketDemo {
    public static void main(String[] args) {
        Ticket t1 = new Ticket();

        t1.start();
        t1.start();
        t1.start();
        t1.start();
    }
}

class Ticket extends Thread{
    //初始化票数
    private  int tick = 100;
    @Override
    public void run() {
        while (true){
            if(tick > 0){
                System.out.println(currentThread().getName()+"--已售出:"+tick--);
            }
        }
    }
}

运行结果:

image.png

我们可以看出虽然100张票卖完了,但是会出现异常而且只有一个线程。这是因为线程已经start,多次start会出现线程状态异常。

2、实现Runnable接口 

这时我们采用实现Runnable接口的方式

/**
 * @Author: wjy329
 * @Time: 2018/8/16下午9:44
 */

public class TicketDemo1 {
    public static void main(String[] args) {
        Ticket1 t = new Ticket1();

       Thread t1 = new Thread(t);
       Thread t2 = new Thread(t);
       Thread t3 = new Thread(t);
       Thread t4 = new Thread(t);

       t1.start();
       t2.start();
       t3.start();
       t4.start();


    }
}

class Ticket1 implements Runnable{
    //初始化票数
    private  int tick = 1000;
    @Override
    public void run() {
        while (true){
            if(tick > 0){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"--已售出:"+tick--);
            }
        }
    }
}

image.png

看运行结果,发现出现了-1、-2,这意味着线程出现了安全问题。

tick属于共享数据,当1线程售出1时,此时tick>0,线程0,2,3进入,在执行减减操作,会出现负数。

3、synchronized

当我们采用synchronized时,即可保证线程安全;

/**
 * @Author: wjy329
 * @Time: 2018/8/16下午9:44
 */
public class TicketDemo1 {
    public static void main(String[] args) {
        Ticket1 t = new Ticket1();

       Thread t1 = new Thread(t);
       Thread t2 = new Thread(t);
       Thread t3 = new Thread(t);
       Thread t4 = new Thread(t);

       t1.start();
       t2.start();
       t3.start();
       t4.start();


    }
}

class Ticket1 implements Runnable{
    //初始化票数
    private  int tick = 1000;
    @Override
    public void run() {
        while (true){
            synchronized (this){
                if(tick > 0){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"--已售出:"+tick--);
                }
            }
        }
    }
}

image.png

此时,通过4个线程将所有的票卖完。

后面再详细写synchronized

Java多线程学习(一)之线程的创建方式

线程是进程中的一个独立的控制单元。

一、创建线程的方式

1、继承Thread类

步骤:

    1、定义类继承Thread

    2、复写run方法

    3、调用线程的start方法;

public class ThreadTest1 {
    public static void main(String[] args) {
        ThreadDemo demo = new ThreadDemo();
        demo.start();
    }

}

class ThreadDemo extends Thread{
    @Override
    public void run() {
    //run方法中放需要执行的代码
        System.out.println("run---");
    }
}

2、实现Runnable接口

步骤:

    1、定义类实现Runnable接口

    2、覆盖run方法

    3、通过Thread类创建线程对象

    4、将Runnable接口的子类对象作为实际参数传递给Thread的构造函数

    5、调用Thread类的start方法开启线程

public class ThreadTest2{
    public static void main(String[] args) {
      ThreadDemo1 threadDemo1 = new ThreadDemo1();
      Thread t1 = new Thread(threadDemo1);
      t1.start();
    }
}

class ThreadDemo1 implements Runnable{
    @Override
    public void run() {
        for(int i=0;i<600;i++){
            System.out.println(Thread.currentThread().getName()+"run---"+i);
        }
    }
}

Apache WordPress启用https

1、证书申请

在阿里云控制台的产品与服务中选择SSL证书

image.png

点开一开,挖槽,这么贵,其实是有免费的,哈哈哈。

如图,点击Symantec-增强型OV SSL-免费型DV SSL,这就免费了。

123.gif

然后点击补全

image.png

填写域名

image.png

选择DNS系统生成的CSR

image.png

然后具体配置:阿里云-官方文档

2、下载及上传证书

当审核通过后,下载证书,并解压

image.png

apache的安装目录下新建cert文件夹,将四个文件都上传到cert文件夹中。

3、修改配置

进入/usr/local/apache2/conf/extra 文件夹,然后编辑httpd-ssl.conf,即 vim httpd-ssl.conf ,按图示修改一部分

DocumentRoot /yjdata/www/www
ServerName www.wjy329.com
ServerAlias wjy329.com
ServerAdmin you@example.com
ErrorLog "/usr/local/apache2/logs/error_log"
TransferLog "/usr/local/apache2/logs/access_log"
ProxyPassMatch ^/(.*\.php)$ fcgi://127.0.0.1:10000/yjdata/www/www/$1
        DirectoryIndex index.html index.php

image.png

image.png

修改 /usr/local/apache2/conf/httpd.conf,都改为自己的目录;

<Directory "/yjdata/www/www">
AllowOverride All
Require all granted
</Directory>
DocumentRoot "/yjdata/www/www"
<Directory "/yjdata/www/www">

image.png

然后重启 服务 –    service httpd restart

cd /yjdata/www/www  vim wp-config.php

在 if( !defined('ABSPATH')) 之前添加两行

define('FORCE_SSL_ADMIN', true); //启用登录时使用ssl
define('FORCE_SSL_LOGIN', true); //后台管理也使用ssl
/** WordPress目录的绝对路径。 */
if ( !defined('ABSPATH') )
        define('ABSPATH', dirname(__FILE__) . '/');

然后便可以用https进行访问

4、安装插件

搜索 Really Simple SSL 插件,点击启用后,完美配置https。

JS常用时间操作

时间戳转格式

//昨天日期
var yesterdayDate=new Date(new Date - 1000 * 60 * 60 * 24);
var yesterday=formatDate(yesterdayDate);
//昨天往前一周的时间
var lastWeekDate=new Date(new Date - 1000 * 60 * 60 * 24 * 7);
var lastWeek=formatDate(lastWeekDate);
//时间转化
function formatDate(date) {
    var y = date.getFullYear();
    var m = date.getMonth() + 1;
    m = m < 10 ? '0' + m : m;
    var d = date.getDate();
    d = d < 10 ? ('0' + d) : d;
    return y + '-' + m + '-' + d;
}

这样就可以将时间戳输出为 yy-MM-dd 的格式。

时间格式转换

var oldTime = (new Date(value)).getTime();
var curTime = new Date(oldTime).Format("yyyy-MM-dd");
return curTime;


Date.prototype.Format = function (fmt) {
    var o = {
        "M+": this.getMonth() + 1, //月份 
        "d+": this.getDate(), //日 
        "h+": this.getHours(), //小时 
        "m+": this.getMinutes(), //分 
        "s+": this.getSeconds(), //秒 
        "q+": Math.floor((this.getMonth() + 3) / 3), //季度 
        "S": this.getMilliseconds() //毫秒 
    };
    if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    for (var k in o)
    if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
    return fmt;
}