浅川好孩子

浅川好孩子 查看完整档案

北京编辑河南大学  |  __ 编辑  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 个人简介什么都没有

个人动态

浅川好孩子 发布了文章 · 4月10日

探花07

sparkmlib

最小二乘法ALS

7.4.2、数据建模

ALS算法的第二步就是数据建模,其实在MLlib算法库中有可以直接使用的训练算法,ALS.tran方法源码
如下:
image.png

package cn.itcast.spark;

import jdk.nashorn.internal.ir.IdentNode;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.mllib.recommendation.ALS;
import org.apache.spark.mllib.recommendation.MatrixFactorizationModel;
import org.apache.spark.mllib.recommendation.Rating;

public class MyRecommend {

    public static void main(String[] args) {

        SparkConf sparkConf = new SparkConf()
                .setAppName("MyRecommend")
                .setMaster("local[*]");
        JavaSparkContext jsc = new JavaSparkContext(sparkConf);
        jsc.setLogLevel("WARN"); //设置日志级别

        //读取数据文件
        JavaRDD<String> sourceRDD = jsc.textFile("F:\\ml-100k\\u.data");

        //对文件做分割的处理 \t
        JavaRDD<String[]> lineRdd = sourceRDD.map(v -> v.split("\t"));

        // 转化得到Rating对象集
        JavaRDD<Rating> ratingRDD = lineRdd.map(v -> new Rating(Integer.valueOf(v[0]), Integer.valueOf(v[1]), Double.valueOf(v[2])));

        // 训练模型
        MatrixFactorizationModel model = ALS.train(ratingRDD.rdd(), 8, 10);

        //商品推荐
        Rating[] products = model.recommendProducts(301, 10);

        // 打印结果集
        for (Rating product : products) {
            System.out.println("userId = "+ product.user() +", product = " + product.product());
        }

        jsc.stop();

    }

}

推荐结果
image.png

查看原文

赞 0 收藏 0 评论 0

浅川好孩子 发布了文章 · 4月8日

centos开放端口

1、开放端口

firewall-cmd --zone=public --add-port=5672/tcp --permanent   # 开放5672端口

firewall-cmd --zone=public --remove-port=5672/tcp --permanent  #关闭5672端口

firewall-cmd --reload   # 配置立即生效

2、查看防火墙所有开放的端口

firewall-cmd --zone=public --list-ports

关闭防火墙

systemctl stop firewalld.service

关闭防火墙的服务

systemctl stop firewalld.service

查看防火墙状态

firewall-cmd --state

5、查看监听的端口

PS:centos7默认没有 netstat 命令,需要安装 net-tools 工具,yum install -y net-tools

netstat -lnpt

image.png

7、查看进程的详细信息

ps 6832

image.png

8、中止进程

kill -9 6832
查看原文

赞 0 收藏 0 评论 0

浅川好孩子 发布了文章 · 4月8日

探花06

安装jdk

1、在/usr/local 目录下新建Java文件夹

mkdir /usr/local/java

将jdk拷贝到 /usr/local/java  进入到java文件夹,解压压缩包

tar -zxvf jdk-8u281-linux-x64.tar.gz 

2、设置环境变量  这里采用全局设置方法,就是修改etc/profile,它是是所有用户的共用的环境变量  找到/etc/profile,编辑,在末尾添加

# java的配置
export JAVA_HOME=/usr/local/java/jdk1.8.0_281/
export JRE_HOME=/usr/local/java/jdk1.8.0_281/jre
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
export PATH=$JAVA_HOME/bin:$PATH

在上述添加过程中,等号两侧不要加入空格,不然会出现“不是有效的标识符”,因为source /etc/profile 时不能识别多余到空格,会理解为是路径一部分。

然后保存。

运行以下命令,使profile生效。

source /etc/profile

3、检验是否成功  在终端


java -version
javac

spark的环境准备

image.png
在hosts文件中添加节点的映射:

vim /etc/hosts
192.168.31.82 itcast
192.168.31.82 node1 node01
192.168.31.83 node2 node02
192.168.31.84 node3 node03
#关闭防火墙
systemctl stop firewalld.service
#禁止开机启动
systemctl disable firewalld.service

修改hosts文件后

/etc/init.d/network restart

即可生效
image.png

免密登录

在node1上

生成秘钥,一路回车

ssh-keygen
ssh-copy-id node1
ssh-copy-id node2
ssh-copy-id node3

部署集群

调整机器时间
image.png
date命令查看时间

#创建安装目录,3台机器都要创建 
mkdir /itcast
#上传spark-2.4.3-bin-hadoop2.7.tgz到该目录,进行解压
tar -xvf spark-2.4.3-bin-hadoop2.7.tgz
mv spark-2.4.3-bin-hadoop2.7 spark
#修改配置 
cd spark/conf
mv spark-env.sh.template spark-env.sh
vim spark-env.sh
#在最上面插入如下信息(3台机器都是如此)
export JAVA_HOME=/usr/local/src/java/jdk1.8.0_141 #jdk地址
export SPARK_MASTER_HOST=node1 #指定master的主机名
export SPARK_MASTER_PORT=7077#master的端口
mv slaves.template slaves vim slaves
#输入如下内容(3台机器都是如此)
node1 node2 node3
#远程拷贝到其它机器
scp -r spark node2:/itcast/ scp -r spark node3:/itcast/
#添加环境变量(3台都添加)
vim /etc/profile
export SPARK_HOME=/itcast/spark
export PATH=$PATH:$SPARK_HOME/bin
export PATH=$PATH:$SPARK_HOME/sbin
source /etc/profile
#启动(只在node1节点启动即可)
cd /itcast/spark/sbin ./start-all.sh

image.png

这个jdk需要根据自己电脑的配置进行设置

启动集群后查看
image.png

image.png

启动spark后在主从机上查看
image.png
image.png

Spark高可用搭建

# 修改三台机器的host文件
vim /etc/hosts
#添加zookeeper的ip,并起名叫zk

#修改spark配置
vim spark-env.sh
export SPARK_MASTER_HOST=node1 #把这个注释掉
#增加ZooKeeper的配置
export SPARK_DAEMON_JAVA_OPTS="-Dspark.deploy.recoveryMode=ZOOKEEPER -Dspark.deploy.zookeeper.url=zk:2181 -Dspark.deploy.zookeeper.dir=/spark"

参数说明:
spark.deploy.recoveryMode:恢复模式(Master 重新启动的模式)
有三种:(1) ZooKeeper (2) FileSystem (3) NONE
spark.deploy.zookeeper.url:ZooKeeper 的Server 地址
spark.deploy.zookeeper.dir:保存集群元数据信息的文件、目录。包括Worker,Driver 和
Application。
进入/itacst/spark/conf下边
有个spark-env.sh
image.png
发现模式是通过revoveryMode=zookeeper
修改完spark-env.sh后,
在三台机器上停掉所有的服务

./stop-all.sh

182
image.png
184
image.png

启动集群

#启动HA集群,不能通过start-all.sh的方式启动,会导致找不到master #首先,将3台机器的master启动起来
./sbin/start-master.sh
#然后,分别启动每个机器上的slave
./start-slave.sh spark://node1:7077
#这里的node1是当前的master,需要通过zk中查看 哪个机器是master #最后就可以通过停止master的方式进行测试了

启动集群后的结果
image.png

spark应用入门

word.txt

hello world
hello spring
hello mvc
hello spark

1

package cn.itcast.spark;

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import scala.Int;
import scala.Tuple2;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class WordCountApp {

    public static void main(String[] args) {

        // spark的配置
        SparkConf sparkConf = new SparkConf()
                .setAppName("WordCountApp")
                .setMaster("local[*]"); //本地模式,并且使用和cpu的内核数相同的线程数进行执行

        // 定义上下文对象,它是程序的入口
        JavaSparkContext jsc = new JavaSparkContext(sparkConf);

        // 读取文件
        JavaRDD<String> fileRdd = jsc.textFile("F://code//word.txt");

        // 压扁操作,并且按照空格分割
        JavaRDD<String> flatMapRdd = fileRdd.flatMap(new FlatMapFunction<String, String>() {
            @Override
            public Iterator<String> call(String s) throws Exception {
                String[] ss = s.split(" ");
                return Arrays.asList(ss).iterator();
            }
        });

        // 对单词做计数
        JavaPairRDD<Object, Integer> mapToPairRdd = flatMapRdd.mapToPair(new PairFunction<String, Object, Integer>() {
            @Override
            public Tuple2<Object, Integer> call(String s) throws Exception {
                return new Tuple2<>(s, 1);
            }
        });

        // 对相同的单词做相加操作
        JavaPairRDD<Object, Integer> reduceByKeyRdd = mapToPairRdd.reduceByKey(new Function2<Integer, Integer, Integer>() {
            @Override
            public Integer call(Integer v1, Integer v2) throws Exception {
                return v1 + v2;
            }
        });

        // 执行计算
        List<Tuple2<Object, Integer>> collect = reduceByKeyRdd.collect();
        for (Tuple2<Object, Integer> obj : collect) {
            System.out.println(obj._1() + "出现的次数为:"+ obj._2());
        }


        // 关闭,释放资源
        jsc.stop();
    }
}

2 连贯操作


package cn.itcast.spark;

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import scala.Tuple2;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class WordCountApp2 {

    public static void main(String[] args) {

        // spark的配置
        SparkConf sparkConf = new SparkConf()
                .setAppName("WordCountApp2")
                .setMaster("local[*]"); //本地模式,并且使用和cpu的内核数相同的线程数进行执行

        // 定义上下文对象,它是程序的入口
        JavaSparkContext jsc = new JavaSparkContext(sparkConf);

        // 读取文件
        JavaRDD<String> fileRdd = jsc.textFile("F://code//word.txt");

        // 单词计数的逻辑处理
        List<Tuple2<String, Integer>> list = fileRdd.flatMap(s -> {
            String[] ss = s.split(" ");
            return Arrays.asList(ss).iterator();
        }).mapToPair(s -> new Tuple2<>(s, 1))
                .reduceByKey((v1, v2) -> v1 + v2)
                .collect();


        // 遍历输出
        list.forEach(obj -> System.out.println(obj._1() + "出现的次数为:" + obj._2()));


        // 关闭,释放资源
        jsc.stop();
    }
}


3 打包到线上运行


package cn.itcast.spark;

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import scala.Tuple2;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class WordCountApp3 {

    public static void main(String[] args) {

        // spark的配置
        SparkConf sparkConf = new SparkConf()
                .setAppName("WordCountApp");
//                .setMaster("local[*]"); //本地模式,并且使用和cpu的内核数相同的线程数进行执行

        // 定义上下文对象,它是程序的入口
        JavaSparkContext jsc = new JavaSparkContext(sparkConf);

        // 读取文件
        JavaRDD<String> fileRdd = jsc.textFile(args[0]);

        // 压扁操作,并且按照空格分割
        JavaRDD<String> flatMapRdd = fileRdd.flatMap(new FlatMapFunction<String, String>() {
            @Override
            public Iterator<String> call(String s) throws Exception {
                String[] ss = s.split(" ");
                return Arrays.asList(ss).iterator();
            }
        });

        // 对单词做计数
        JavaPairRDD<Object, Integer> mapToPairRdd = flatMapRdd.mapToPair(new PairFunction<String, Object, Integer>() {
            @Override
            public Tuple2<Object, Integer> call(String s) throws Exception {
                return new Tuple2<>(s, 1);
            }
        });

        // 对相同的单词做相加操作
        JavaPairRDD<Object, Integer> reduceByKeyRdd = mapToPairRdd.reduceByKey(new Function2<Integer, Integer, Integer>() {
            @Override
            public Integer call(Integer v1, Integer v2) throws Exception {
                return v1 + v2;
            }
        });

        // 保存结果到指定的目录或文件
        reduceByKeyRdd.saveAsTextFile(args[1]);


        // 关闭,释放资源
        jsc.stop();
    }
}

打包到集群上运行

image.png
image.png
cd /itcast/bin下

./spark-submit --master spark://node1:7077 --class cn.itcast.spark.WordCountApp3 /itcast/my-spark-test-1.0-SNAPSHOT.jar /itcast/word.txt /itcast/wc

查看运行后的结果

cat part-00000 part-00001

image.png

弹性分布式数据集RDD

6.1、RDD概述
6.1.1、什么是RDD
RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是Spark中最基本的数据抽象,它代表
一个不可变、可分区、里面的元素可并行计算的集合。RDD具有数据流模型的特点:自动容错、位置感
知性调度和可伸缩性。RDD允许用户在执行多个查询时显式地将数据缓存在内存中,后续的查询能够重
用这些数据,这极大地提升了查询速度。
Dataset:一个数据集合,用于存放数据的。
Distributed:RDD中的数据是分布式存储的,可用于分布式计算。
Resilient:RDD中的数据可以存储在内存中或者磁盘中。
6.1.2、为什么会产生RDD?
传统的MapReduce虽然具有自动容错、平衡负载和可拓展性的优点,但是其最大缺点是采用非循
环式的数据流模型,使得在迭代计算中要进行大量的磁盘IO操作。RDD正是解决这一缺点的抽象
方法。
RDD是Spark提供的最重要的抽象的概念,它是一种具有容错机制的特殊集合,可以分布在集群的
节点上,以函数式编程来操作集合,进行各种并行操作。可以把RDD的结果数据进行缓存,方便
进行多次重用,避免重复计算。
6.2、RDD的类型
Spark中的操作大致可以分为四类操作,分别是创建操作、转换操作、控制操作和行为操作。
创建操作:用于RDD创建工作,RDD的创建只有两种方法:
一种是来自于内存集合和外部存储系统
通过转换操作生成的RDD
转换操作:将RDD通过一定的操作变换成新的RDD
比如:RDD通过flatMap操作后得到新的RDD
控制操作:进行RDD持久化,可以让RDD按不同的存储策略保存在磁盘或者内存中。
行为操作:能够触发Spark的运行操作,比如:collect的操作就是行为操作

map

map是对RDD中的每个元素都执行一个指定的函数来产生一个新的RDD。 任何原RDD中的元素在新
RDD中都有且只有一个元素与之对应。
连贯操作变量的数据类型跟初始的RDD中的数据类型一致


@Test
public void testMap() {
    SparkConf sparkConf = new SparkConf()
            .setAppName("RddOperation")
            .setMaster("local[*]");
    JavaSparkContext jsc = new JavaSparkContext(sparkConf);

    // 生成一个测试rdd数据集
    JavaRDD<Integer> rdd1 = jsc.parallelize(Arrays.asList(1, 2, 3, 4, 5));



    // 将rdd1中每一个元素都乘以2,生成新的rdd
//        JavaRDD<Integer> rdd2 = rdd1.map(new MyFunction()); 方案一
    JavaRDD<Integer> rdd2 = rdd1.map(v1 -> v1 * 2); //方案二

    List<Integer> list = rdd2.collect();
    list.forEach(integer -> System.out.println(integer));

    jsc.stop();
}
    

结果是遍历输出2,4,6,8,10

filter

filter 是对RDD中的每个元素都执行一个指定的函数来过滤产生一个新的RDD。 任何原RDD中的元素在
新RDD中都有且只有一个元素与之对应。

连贯操作变量的数据类型跟初始的RDD中的数据类型一致


@Test
public void testFilter(){
    SparkConf sparkConf = new SparkConf()
            .setAppName("RddOperation")
            .setMaster("local[*]");
    JavaSparkContext jsc = new JavaSparkContext(sparkConf);

    // 生成一个测试rdd数据集
    JavaRDD<Integer> rdd1 = jsc.parallelize(Arrays.asList(1, 2, 3, 4, 5));

    // 过滤数据,用大于2的数据组成一个新的rdd
    JavaRDD<Integer> rdd2 = rdd1.filter(v1 -> v1 > 2);

    List<Integer> list = rdd2.collect();

    list.forEach(integer -> System.out.println(integer));

    jsc.stop();
}

结果输出3,4,5

flatMap

与map类似,区别是原RDD中的元素经map处理后只能生成一个元素,而原RDD中的元素经flatmap处
理后可生成多个元素来构建新RDD。 举例:对原RDD中的每个元素x产生y个元素(从1到y,y为元素x
的值)

连贯操作中变量返回迭代器Iterator<Object>


    @Test
    public void testFlatMap() {
        SparkConf sparkConf = new SparkConf()
                .setAppName("RddOperation")
                .setMaster("local[*]");
        JavaSparkContext jsc = new JavaSparkContext(sparkConf);
        // 生成RDD
        JavaRDD<String> rdd = jsc.parallelize(Arrays.asList("hello world","hello spark"));
        // 数据压扁操作
        JavaRDD<String> rdd2 = rdd.flatMap(s -> Arrays.asList(s.split(" ")).iterator());

        //收集数据
        List<String> list = rdd2.collect();
        for (String o : list) {
            System.out.println(o);
        }
    }

结果是
hello
spark
hello
world

mapPartitions

mapPartitions是map的一个变种。map的输入函数是应用于RDD中每个元素,而mapPartitions的输
入函数是应用于每个分区,也就是把每个分区中的内容作为整体来处理的。
将一个数据集合分成若干个区

连贯操作中变量返回迭代器Iterator<Object>

    @Test
    public void testMapPartitions (){
        SparkConf sparkConf = new SparkConf()
                .setAppName("RddOperation")
                .setMaster("local[*]");
        JavaSparkContext jsc = new JavaSparkContext(sparkConf);
        // 生成RDD,分3个区存储
        JavaRDD<Integer> rdd = jsc.parallelize(Arrays.asList(1,2,3,4,5,6,7,8,9,10),3);
        // 分区操作数据
        JavaRDD<Integer> rdd2 = rdd.mapPartitions(integerIterator -> {
            List<Integer> result = new ArrayList<>();
            while (integerIterator.hasNext()){
                Integer i = integerIterator.next();
                result.add(i);
            }
            System.out.println("分区数据:" + result);
            return result.iterator();
        });

        //收集数据
        List<Integer> list = rdd2.collect();
        list.forEach(integer ->  System.out.println(integer));
    }

结果如下所示
image.png

mapToPair

此函数会对一个RDD中的每个元素调用f函数,其中原来RDD中的每一个元素都是T类型的,调用f函数
后会进行一定的操作把每个元素都转换成一个<K2,V2>类型的对象
连贯操作返回的变量的数据类型是new Tuple<Object,Object>


    @Test
    public void testMapToPair (){
        SparkConf sparkConf = new SparkConf()
                .setAppName("RddOperation")
                .setMaster("local[*]");
        JavaSparkContext jsc = new JavaSparkContext(sparkConf);
        // 生成RDD
        JavaRDD<String> rdd = jsc.parallelize(Arrays.asList("hello world","hello spark"));

        // 按照空格分割
        JavaRDD<String> rdd1 = rdd.flatMap(s -> Arrays.asList(s.split(" ")).iterator());

        // 把每一个单词的出现数量标记为1
        JavaPairRDD<Object, Object> rdd2 = rdd1.mapToPair(s -> new Tuple2<>(s, 1));

        //收集数据
        List<Tuple2<Object, Object>> list = rdd2.collect();
        for (Tuple2<Object, Object> o : list) {
            System.out.println(o);
        }
    }
    

image.png

reduceByKey

顾名思义,reduceByKey就是对元素为KV对的RDD中Key相同的元素的Value进行reduce,因此,Key
相同的多个元素的值被reduce为一个值,然后与原RDD中的Key组成一个新的KV对。


    @Test
    public void testReduceByKey (){
        SparkConf sparkConf = new SparkConf()
                .setAppName("RddOperation")
                .setMaster("local[*]");
        JavaSparkContext jsc = new JavaSparkContext(sparkConf);
        // 生成RDD
        JavaRDD<String> rdd = jsc.parallelize(Arrays.asList("hello world","hello spark"));

        // 按照空格分割
        JavaRDD<String> rdd1 = rdd.flatMap(s -> Arrays.asList(s.split(" ")).iterator());

        // 把每一个单词的出现数量标记为1
        JavaPairRDD<Object, Integer> rdd2 = rdd1.mapToPair(s -> new Tuple2<>(s, 1));

        // 按照key相同的数进行相加操作
        JavaPairRDD<Object, Integer> rdd3 = rdd2.reduceByKey((v1, v2) -> v1 + v2);

        //收集数据
        List<Tuple2<Object, Integer>> list = rdd3.collect();
        for (Tuple2<Object, Integer> o : list) {
            System.out.println(o);
        }
    }

结果是
image.png

coalesce

该函数用于将RDD进行重分区,使用HashPartitioner。第一个参数为重分区的数目,第二个为是否进
行shuffle,默认为false;


    @Test
    public void testCoalesce (){
        SparkConf sparkConf = new SparkConf()
                .setAppName("RddOperation")
                .setMaster("local[*]");
        JavaSparkContext jsc = new JavaSparkContext(sparkConf);
        // 生成RDD
        JavaRDD<Integer> rdd = jsc.parallelize(Arrays.asList(1,2,3,4,5,6,7,8,9,10));

        System.out.println(rdd.getNumPartitions()); //4
        // 重新分区,shuffle:是否重新分配存储,如果分区数大于原有分区数,就需要设置为true
        JavaRDD<Integer> rdd2 = rdd.coalesce(6, true);
        System.out.println(rdd2.getNumPartitions()); //2

        //收集数据
        List<Integer> list = rdd2.collect();
        for (Integer o : list) {
            System.out.println(o);
        }
    }
查看原文

赞 0 收藏 0 评论 0

浅川好孩子 发布了文章 · 4月7日

探花05

mybatis-plusBUG:java.lang.NoSuchMethodException: com.baomidou.mybatisplus.core.metadata.IPage.<init>

三翼黑崎 2020-04-14 13:50:44 1902 收藏
文章标签: bug
版权
问题描述
如题服务器运行时报 java.lang.NoSuchMethodException: com.baomidou.mybatisplus.core.metadata.IPage.()

解决方案
mybatis-plus 版本太低,我是3.0.5,建议升级版本,我升级到3.2.0+

<dependency>
   <groupId>joda-time</groupId>
   <artifactId>joda-time</artifactId>
   <version>2.9.8</version>
</dependency>

1.初始化时间

DateTime time = new DateTime(2018,4,23,23, 7,18,888);

// 2018年4月23日23点7分18秒888毫秒
2.按格式输出时间(将DateTime格式转换为字符串)

 String time = dateTime.toString("yyyy-MM-dd hh:mm:ss.SSSa");

小写hh是12小时制,大写HH是24小时制

3.将字符串转换为DateTime格式

 DateTimeFormatter format = DateTimeFormat .forPattern("yyyy-MM-dd HH:mm:ss");  
                   
 DateTime dateTime = DateTime.parse("2018-4-23 23:12:16", format); 

4.取得当前时间

DateTime time= new DateTime();

5.计算两个日期间隔的天数

 LocalDate start=new LocalDate(2018,4,23);    
 LocalDate end=new LocalDate(2019, 06, 16);    
 int days = Days.daysBetween(start, end).getDays(); 
6.增加日期
DateTime dateTime = DateTime.parse("2018-04-23");  
dateTime = dateTime1.plusDays(1);  
dateTime = dateTime1.plusHours(2);  
dateTime = dateTime1.plusMinutes(3);  
dateTime = dateTime1.plusMonths(4);  
dateTime = dateTime1.plusSeconds(5);  
dateTime = dateTime1.plusWeeks(6);  
dateTime = dateTime1.plusYears(7);  

7.减少日期

DateTime dateTime = DateTime.parse("2018-04-23");  
dateTime = dateTime1.minusMillis(1);  
dateTime = dateTime1.minusHours(1);  
dateTime = dateTime1.minusSeconds(1);;  

8.判断是否闰月

DateTime time = new DateTime();    
org.joda.time.DateTime.Property month = time.monthOfYear();    
System.out.println("是否闰月:" + month.isLeap());  

9.DateTime与Date转换

DateTime time = new DateTime(new Date());    
Date date = time.toDate();    
DateTime time2 = new DateTime(System.currentTimeMillis());    
time2.getMillis();  

10.DateTime与Calendar转换

Calendar calendar = Calendar.getInstance();    
dateTime = new DateTime(calendar);
查看原文

赞 0 收藏 0 评论 0

浅川好孩子 发布了文章 · 3月31日

探花04

FastDFS环境搭建

创建tracker容器

docker run -d --network=host --name tracker -v /var/fdfs/tracker:/var/fdfs delron/fastdfs tracker

创建storage容器

docker run -d --network=host --name storage -e TRACKER_SERVER=192.168.31.81:22122 -v /var/fdfs/storage:/var/fdfs -e GROUP_NAME=group1 delron/fastdfs storage

进入storage容器,到storage的配置文件中配置http访问的端口,配置文件在/etc/fdfs目录下 的storage.conf。

docker exec -it storage /bin/bash

默认的http端口为8888,可以修改也可以配置# the port of the web server on this storage server http.server_port=8888

配置nginx,在/usr/local/nginx目录下,修改nginx.conf文件 #默认配置如下:

server { 
    listen 8888;
    server_name localhost;
    location ~/group[0-9]/ {
        ngx_fastdfs_module;
    }
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root html;
    } 
}

默认的存储路径为/var/fdfs/data

导入依赖

<dependency>
    <groupId>com.github.tobato</groupId>
    <artifactId>fastdfs-client</artifactId>
    <version>1.26.7</version>
    <exclusions>
        <exclusion>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
        </exclusion>
    </exclusions>
</dependency>

application.properties


fdfs.so-timeout = 1501
fdfs.connect-timeout = 601
#缩略图生成参数
fdfs.thumb-image.width= 150
fdfs.thumb-image.height= 150
#TrackerList参数,支持多个
fdfs.tracker-list=192.168.31.81:22122

测试

package com.tanhua.server;

import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import org.apache.commons.io.FileUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.File;
import java.io.IOException;

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestFastDFS {

    @Autowired
    protected FastFileStorageClient storageClient;

    @Test
    public void testUpload(){
        String path = "C:\\Users\\zhijun\\Desktop\\pics\\1.jpg";
        File file = new File(path);

        try {
            StorePath storePath = this.storageClient.uploadFile(FileUtils.openInputStream(file), file.length(), "jpg", null);

            System.out.println(storePath); //StorePath [group=group1, path=M00/00/00/wKgfUV2GJSuAOUd_AAHnjh7KpOc1.1.jpg]
            System.out.println(storePath.getFullPath());//group1/M00/00/00/wKgfUV2GJSuAOUd_AAHnjh7KpOc1.1.jpg
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
查看原文

赞 0 收藏 0 评论 0

浅川好孩子 发布了文章 · 3月30日

探花03

统一处理token
在之前的开发中,我们会在每一个Service中对token做处理,相同的逻辑一定是要进行统一处理的,接
下来我们将使用拦截器+ThreadLocal的方式进行解决。

注册RestTemplate

package com.tanhua.server.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.Charset;

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
        RestTemplate restTemplate = new RestTemplate(factory);
        // 支持中文编码
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(Charset.forName("UTF-8")));
        return restTemplate;
    }

    @Bean
    public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setReadTimeout(5000);//单位为ms
        factory.setConnectTimeout(5000);//单位为ms
        return factory;
    }
}

编写UserThreadLocal

package com.tanhua.server.utils;

import com.tanhua.server.pojo.User;

public class UserThreadLocal {

    private static final ThreadLocal<User> LOCAL = new ThreadLocal<>();

    private UserThreadLocal() {

    }

    public static void set(User user) {
        LOCAL.set(user);
    }

    public static User get() {
        return LOCAL.get();
    }
}

编写TokenInterceptor

package com.tanhua.server.interceptor;

import com.tanhua.server.pojo.User;
import com.tanhua.server.service.UserService;
import com.tanhua.server.utils.NoAuthorization;
import com.tanhua.server.utils.UserThreadLocal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class TokenInterceptor implements HandlerInterceptor {

    @Autowired
    private UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //判断,请求的方法是否包含了 NoAuthorization ,如果包含了,就不需要做处理
        if(handler instanceof HandlerMethod){
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            NoAuthorization annotation = handlerMethod.getMethod().getAnnotation(NoAuthorization.class);
            if(annotation != null){
                return true;
            }
        }

        String token = request.getHeader("Authorization");
        User user = this.userService.queryUserByToken(token);
        if(null == user){
            response.setStatus(401); //无权限
            return false;
        }

        // 存储到当前的线程中
        UserThreadLocal.set(user);
        return true;
    }
}

编写注解NoAuthorization


package com.tanhua.server.utils;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented //标记注解
public @interface NoAuthorization {

}

注册拦截器


package com.tanhua.server.config;

import com.tanhua.server.interceptor.RedisCacheInterceptor;
import com.tanhua.server.interceptor.TokenInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private RedisCacheInterceptor redisCacheInterceptor;

    @Autowired
    private TokenInterceptor tokenInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //注意拦截器的顺序
        registry.addInterceptor(this.tokenInterceptor).addPathPatterns("/**");
        registry.addInterceptor(this.redisCacheInterceptor).addPathPatterns("/**");
    }
}
查看原文

赞 0 收藏 0 评论 0

浅川好孩子 发布了文章 · 3月29日

探花02

docker 安装mongodb

#拉取镜像
docker pull mongo:4.0.3
#创建容器
docker create --name mongodb --restart=always -p 27017:27017 -v mongodb:/data/db mongo:4.0.3
#启动容器
docker start mongodb
#进入容器 docker exec -it mongodb /bin/bash
#使用MongoDB客户端进行操作
mongo > show dbs 
#查询所有的数据库
admin 0.000GB
config 0.000GB
local 0.000GB

Collections自定义排序

//倒序排列
Collections.sort(todayBests, (o1, o2) -> Long.valueOf(o2.getFateValue() - o1.getFateValue()).intValue());

docker安装zookeeper

#查看镜像
docker search zookeeper

下载镜像
docker pull zookeeper

#运行容器
docker run -d \
-p 2181:2181 \
-v /mysoft/zookeeper/data/:/data/ \
--name=zookeeper  \
--privileged zookeeper

image.png

单元测试报错

image.png
忘记了在dubbo接口实现类中加入dubbo的Service的注解

Double转Long

Double.valueOf(score).longValue()

响应结果写入缓存

image.png
因为拦截器执行完以后已经执行了视图的渲染,拿不到响应的结果,我们需要的是处理完controller以后,从响应结果中拿到数据,将数据存到redis
ResponseBodyAdvice会在response执行前进行处理逻辑
image.png

替换request

image.png
image.png

缓存优化


#RedisCacheInterceptor
package com.tanhua.server.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

@Component
public class RedisCacheInterceptor implements HandlerInterceptor {

    private static ObjectMapper mapper = new ObjectMapper();

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Value("${tanhua.cache.enable}")
    private Boolean enable;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        if (!enable) {
            //未开启缓存
            return true;
        }

        String method = request.getMethod();
        if (!StringUtils.equalsAnyIgnoreCase(method, "GET", "POST")) {
            // 非GET、POST的请求不进行缓存处理
            return true;
        }

        // 通过缓存做命中,查询redis,redisKey ?  组成:md5(请求的url + 请求参数)
        String redisKey = createRedisKey(request);
        String data = this.redisTemplate.opsForValue().get(redisKey);
        if (StringUtils.isEmpty(data)) {
            // 缓存未命中
            return true;
        }

        // 将data数据进行响应
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        response.getWriter().write(data);

        return false;
    }

    public static String createRedisKey(HttpServletRequest request) throws
            Exception {
        String paramStr = request.getRequestURI();
        Map<String, String[]> parameterMap = request.getParameterMap();
        if (parameterMap.isEmpty()) {
            //请求体的数据只能读取一次,需要进行包装Request进行解决
            paramStr += IOUtils.toString(request.getInputStream(), "UTF-8");
        } else {
            paramStr += mapper.writeValueAsString(request.getParameterMap());
        }

        String authorization = request.getHeader("Authorization");
        if (StringUtils.isNotEmpty((authorization))) {
            paramStr += "_" + authorization;
        }

        return "SERVER_DATA_" + DigestUtils.md5Hex(paramStr);
    }
}

MyResponseBodyAdvice

package com.tanhua.server.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.time.Duration;

@ControllerAdvice
public class MyResponseBodyAdvice implements ResponseBodyAdvice {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private ObjectMapper mapper = new ObjectMapper();

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        //支持的处理类型,这里仅对get和post进行处理
        return returnType.hasMethodAnnotation(GetMapping.class) || returnType.hasMethodAnnotation(PostMapping.class);
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        try {
            String redisKey = RedisCacheInterceptor.createRedisKey(((ServletServerHttpRequest) request).getServletRequest());
            String redisValue;
            if (body instanceof String) {
                redisValue = (String) body;
            } else {
                redisValue = mapper.writeValueAsString(body);
            }
            //存储到redis中
            this.redisTemplate.opsForValue().set(redisKey, redisValue, Duration.ofHours(1));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return body;
    }
}

MyServletRequestWrapper

package com.tanhua.server.interceptor;

import org.apache.commons.io.IOUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 包装HttpServletRequest
 */
public class MyServletRequestWrapper extends HttpServletRequestWrapper {

    private final byte[] body;

    /**
     * Construct a wrapper for the specified request.
     *
     * @param request The request to be wrapped
     */
    public MyServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        body = IOUtils.toByteArray(super.getInputStream());
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        return new RequestBodyCachingInputStream(body);
    }

    private class RequestBodyCachingInputStream extends ServletInputStream {
        private byte[] body;
        private int lastIndexRetrieved = -1;
        private ReadListener listener;

        public RequestBodyCachingInputStream(byte[] body) {
            this.body = body;
        }

        @Override
        public int read() throws IOException {
            if (isFinished()) {
                return -1;
            }
            int i = body[lastIndexRetrieved + 1];
            lastIndexRetrieved++;
            if (isFinished() && listener != null) {
                try {
                    listener.onAllDataRead();
                } catch (IOException e) {
                    listener.onError(e);
                    throw e;
                }
            }
            return i;
        }

        @Override
        public boolean isFinished() {
            return lastIndexRetrieved == body.length - 1;
        }

        @Override
        public boolean isReady() {
            // This implementation will never block
            // We also never need to call the readListener from this method, as this method will never return false
            return isFinished();
        }

        @Override
        public void setReadListener(ReadListener listener) {
            if (listener == null) {
                throw new IllegalArgumentException("listener cann not be null");
            }
            if (this.listener != null) {
                throw new IllegalArgumentException("listener has been set");
            }
            this.listener = listener;
            if (!isFinished()) {
                try {
                    listener.onAllDataRead();
                } catch (IOException e) {
                    listener.onError(e);
                }
            } else {
                try {
                    listener.onAllDataRead();
                } catch (IOException e) {
                    listener.onError(e);
                }
            }
        }

        @Override
        public int available() throws IOException {
            return body.length - lastIndexRetrieved - 1;
        }

        @Override
        public void close() throws IOException {
            lastIndexRetrieved = body.length - 1;
            body = null;
        }
    }
}

RequestReplaceFilter

package com.tanhua.server.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 替换Request对象
 */
@Component
public class RequestReplaceFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if (!(request instanceof MyServletRequestWrapper)) {
            request = new MyServletRequestWrapper(request);
        }
        filterChain.doFilter(request, response);
    }
}
查看原文

赞 0 收藏 0 评论 0

浅川好孩子 发布了文章 · 3月26日

探花交友01

docker 安装redis集群

#部署Redis集群,该集群有3个节点
docker create --name redis-node01 --net host -v redis-node01:/data redis:5.0.2 --cluster-enabled yes --cluster-config-file nodes-node-01.conf --port 6379

docker create --name redis-node02 --net host -v redis-node02:/data redis:5.0.2 --cluster-enabled yes --cluster-config-file nodes-node-02.conf --port 6380

docker create --name redis-node03 --net host -v redis-node03:/data redis:5.0.2 --cluster-enabled yes --cluster-config-file nodes-node-03.conf --port 6381

#启动容器 docker start redis-node01 redis-node02 redis-node03

#进入redis-node01进行操作
docker exec -it redis-node01 /bin/bash

#组建集群
redis-cli --cluster create 192.168.200.146:6379 192.168.200.146:6380 192.168.200.146:6381 --cluster-replicas 0

#查看节点
127.0.0.1:6379>redis-cli
127.0.0.1:6379> CLUSTER NODES
4f4fddc825e2387783fff9c972409b264e4df5d5 192.168.31.81:6381@16381 master - 0 1563956537241 3 connected 10923-16383 0616e00533a16e931f8dfb2e8844c35ca5721dc8 192.168.31.81:6380@16380 master - 0 1563956538243 2 connected 5461-10922 498b986e07731cead17ad1c62aa95dba6513c7b0 192.168.31.81:6379@16379 myself,master - 0 1563956537000 1 connected 0-5460

#重定向
127.0.0.1:6379>redis-cli -c

rocketmq的安装


#部署RocketMQ #拉取镜像
docker pull foxiswho/rocketmq:server-4.3.2
docker pull foxiswho/rocketmq:broker-4.3.2 

#创建nameserver容器
docker create -p 9876:9876 --name rmqserver \
-e "JAVA_OPT_EXT=-server -Xms128m -Xmx128m -Xmn128m" \
-e "JAVA_OPTS=-Duser.home=/opt" \
-v rmqserver-logs:/opt/logs \
-v rmqserver-store:/opt/store \
foxiswho/rocketmq:server-4.3.2 

#创建broker.conf文件
vim /itcast/rmq/rmqbroker/conf/broker.conf
brokerIP1=192.168.200.146
namesrvAddr=192.168.200.146:9876
brokerName=broker_tanhua

#创建broker容器
docker create -p 10911:10911 -p 10909:10909 --name rmqbroker \
-e "JAVA_OPTS=-Duser.home=/opt" \
-e "JAVA_OPT_EXT=-server -Xms128m -Xmx128m -Xmn128m" \
-v /itcast/rmq/rmqbroker/conf/broker.conf:/etc/rocketmq/broker.conf \
-v rmqbroker-logs:/opt/logs \
-v rmqbroker-store:/opt/store \
foxiswho/rocketmq:broker-4.3.2 

#启动容器
docker start rmqserver rmqbroker

#停止删除容器
docker stop rmqbroker rmqserver
docker rm rmqbroker rmqserver

#部署RocketMQ的管理工具
docker pull styletang/rocketmq-console-ng:1.0.0 

#创建并启动容器
docker run -e "JAVA_OPTS=-Drocketmq.namesrv.addr=192.168.200.146:9876 -Dcom.rocketmq.sendMessageWithVIPChannel=false" -p 8082:8080 -t styletang/rocketmq-console-ng:1.0.0

rokcetmq的访问
访问 http://ip:8082
image.png
image.png
image.png

rocketmq的依赖可设置为
spring boot的版本是2.1.3

rocketmq.name-server = 192.168.200.146:9876
rocketmq.producer.group = tanhua

image.png
其中rocketmq-client可省略

mybaits plus的配置
设置基本的抽象类
image.png
抽象类不能被实例化,只能被继承,一个类只能继承一个抽象类
设置字段的自动填充
image.png
image.png
云通讯
image.png

查看原文

赞 0 收藏 0 评论 0

浅川好孩子 发布了文章 · 3月26日

Spring Security 实战干货:自定义异常处理

1. 前言

2. Spring Security 中的异常


Spring Security 中的异常主要分为两大类:一类是认证异常,另一类是授权相关的异常。

2.1 AuthenticationException

AuthenticationException 是在用户认证的时候出现错误时抛出的异常。主要的子类如图:

AuthenticationException.png

根据该图的信息,系统用户不存在,被锁定,凭证失效,密码错误等认证过程中出现的异常都由 AuthenticationException 处理。

2.2 AccessDeniedException

AccessDeniedException 主要是在用户在访问受保护资源时被拒绝而抛出的异常。同 AuthenticationException 一样它也提供了一些具体的子类。如下图:

AccessDeniedException.png

AccessDeniedException 的子类比较少,主要是 CSRF 相关的异常和授权服务异常。

  1. Http 状态对认证授权的规定

Http 协议对认证授权的响应结果也有规定。

3.1 401 未授权状态

HTTP 401 错误 - 未授权(Unauthorized) 一般来说该错误消息表明您首先需要登录(输入有效的用户名和密码)。 如果你刚刚输入这些信息,立刻就看到一个 401 错误,就意味着,无论出于何种原因您的用户名和密码其中之一或两者都无效(输入有误,用户名暂时停用,账户被锁定,凭证失效等) 。总之就是认证失败了。其实正好对应我们上面的 AuthenticationException

3.2 403 被拒绝状态

HTTP 403 错误 - 被禁止(Forbidden) 出现该错误表明您在访问受限资源时没有得到许可。服务器理解了本次请求但是拒绝执行该任务,该请求不该重发给服务器。并且服务器想让客户端知道为什么没有权限访问特定的资源,服务器应该在返回的信息中描述拒绝的理由。一般实践中我们会比较模糊的表明原因。 该错误对应了我们上面的 AccessDeniedException

4. Spring Security 中的异常处理


我们在 Spring Security 实战干货系列文章中的 自定义配置类入口 WebSecurityConfigurerAdapter 一文中提到 HttpSecurity 提供的 exceptionHandling() 方法用来提供异常处理。该方法构造出 ExceptionHandlingConfigurer 异常处理配置类。该配置类提供了两个实用接口:

  • AuthenticationEntryPoint 该类用来统一处理 AuthenticationException 异常
  • AccessDeniedHandler 该类用来统一处理 AccessDeniedException 异常

我们只要实现并配置这两个异常处理类即可实现对 Spring Security 认证授权相关的异常进行统一的自定义处理。

4.1 实现 AuthenticationEntryPoint

json 信息响应。

 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.springframework.http.MediaType;
 import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.web.AuthenticationEntryPoint;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.HashMap;
 
 /**
  * @author dax
  * @since 2019/11/6 22:11
  */
 public class SimpleAuthenticationEntryPoint implements AuthenticationEntryPoint {
     @Override
     public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
 
         //todo your business
         HashMap<String, String> map = new HashMap<>(2);
         map.put("uri", request.getRequestURI());
         map.put("msg", "认证失败");
         response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
         response.setCharacterEncoding("utf-8");
         response.setContentType("application/json,charset=utf-8");
         ObjectMapper objectMapper = new ObjectMapper();
         String resBody = objectMapper.writeValueAsString(map);
         PrintWriter printWriter = response.getWriter();
         printWriter.print(resBody);
         printWriter.flush();
         printWriter.close();
     }
 }复制代码

4.2 实现 AccessDeniedHandler

同样以 json 信息响应。

 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.springframework.http.MediaType;
 import org.springframework.security.access.AccessDeniedException;
 import org.springframework.security.web.access.AccessDeniedHandler;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.HashMap;
 
 /**
  * @author dax
  * @since 2019/11/6 22:19
  */
 public class SimpleAccessDeniedHandler implements AccessDeniedHandler {
     @Override
     public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
         //todo your business
         HashMap<String, String> map = new HashMap<>(2);
         map.put("uri", request.getRequestURI());
         map.put("msg", "认证失败");
         response.setStatus(HttpServletResponse.SC_FORBIDDEN);
         response.setCharacterEncoding("utf-8");
         response.setContentType("application/json,charset=utf-8");
         ObjectMapper objectMapper = new ObjectMapper();
         String resBody = objectMapper.writeValueAsString(map);
         PrintWriter printWriter = response.getWriter();
         printWriter.print(resBody);
         printWriter.flush();
         printWriter.close();
     }
 }复制代码

4.3 个人实践建议

其实我个人建议 Http 状态码 都返回 200 而将 401 状态在 元信息 Map 中返回。因为异常状态码在浏览器端会以 error 显示。我们只要能捕捉到 401403 就能认定是认证问题还是授权问题。

4.4 配置

实现了上述两个接口后,我们只需要在 WebSecurityConfigurerAdapterconfigure(HttpSecurity http) 方法中配置即可。相关的配置片段如下:

 http.exceptionHandling().accessDeniedHandler(new SimpleAccessDeniedHandler()).authenticationEntryPoint(new SimpleAuthenticationEntryPoint())复制代码
  1. 总结

暂无

查看原文

赞 0 收藏 0 评论 0

浅川好孩子 发布了文章 · 3月23日

java date SimpleDateFormat

1.1 Date类(应用)

  • 计算机中时间原点

    1970年1月1日 00:00:00

  • 时间换算单位

    1秒 = 1000毫秒

  • Date类概述

    Date 代表了一个特定的时间,精确到毫秒

  • Date类构造方法

    方法名

    说明

    public Date()

    分配一个 Date对象,并初始化,以便它代表它被分配的时间,精确到毫秒

    public Date(long date)

    分配一个 Date对象,并将其初始化为表示从标准基准时间起指定的毫秒数

  • 示例代码
    public class DateDemo01 {
     public static void main(String[] args) {
     //public Date():分配一个 Date对象,并初始化,以便它代表它被分配的时间,精确到毫秒
     Date d1 = new Date();
     System.out.println(d1);
    ​
     //public Date(long date):分配一个 Date对象,并将其初始化为表示从标准基准时间起指定的毫秒数
     long date = 1000*60*60;
     Date d2 = new Date(date);
     System.out.println(d2);
     }
    }

1.2 Date类常用方法(应用)

查看原文

赞 0 收藏 0 评论 0

认证与成就

  • 获得 29 次点赞
  • 获得 1 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 1 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2018-05-29
个人主页被 2.7k 人浏览