zoukankan      html  css  js  c++  java
  • SpringSecurity登录报错403问题:com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field异常、及 Jackson 的使用

      项目使用SpringSecurity进行安全管理,之前登录接口都是好好的,今天突然验证码登录一直报403,最后发现问题所在,记录一下。

    一、问题背景与解决方案

      因为前端登录注册使用差不多相同的流程,所以使用了 mixins ,表单对象如下:

    loginForm: {
      phoneNum: '',
      password: '',
      repeatPassword: '',  // 最早是没有这个字段的,因为做忘记密码,所以也采用了这个mixin,然后加了这个字段
      code: ''
    },

      问题就出在加的那个字段上,后台SpringSecurity的拦截器上获取请求参数采用的这个方法

    // 登录是否含手机号
    User voUser = new ObjectMapper().readValue(req.getInputStream(), User.class);
    if (voUser == null || voUser.getPhoneNum() == null) {
        throw new AuthenticationServiceException("请输入手机号");
    }

      而我的 User.class 之前没做忘记密码之前,实体类也没加这个字段

    private String repeatPassword;

      所以导致匹配不上这个类,所以报错:com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "repeatPassword"

      解决方案就是:将 repeatPassword 这个字段在实体类上加上即可。

      但是肯定不能这么简单就了事,本着遇到问题就学习的精神,所以把这个 new ObjectMapper().readValue() 这个东西研究一下先。

    二、Jackson 介绍

      new ObjectMapper().readValue() 这个东西来源于 jackson。

    1、jackson是什么

      Java下常见的Json类库有Gson、JSON-lib和Jackson等,Jackson相对来说比较高效,在项目中主要使用Jackson进行JSON和Java对象转换,下面给出一些Jackson的JSON操作方法。

    2、准备工作

      首先去官网下载Jackson工具包,下载地址http://wiki.fasterxml.com/JacksonDownload。Jackson有1.x系列和2.x系列,2.x系列有3个jar包需要下载:

    jackson-core-2.2.3.jar
    jackson-annotations-2.2.3.jar
    jackson-databind-2.2.3.jar

      但是如果使用SpringBoot就很方便啦,不需要这步,因为springboot默认配置的 json 转换工具就是 jackson。

    3、JSON序列化  —— JAVA对象转JSON

    import java.io.IOException;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
     
    import com.fasterxml.jackson.databind.ObjectMapper;
     
    public class JacksonDemo {
        public static void main(String[] args) throws ParseException, IOException {
            User user = new User();
            user.setName("小民");    
            user.setEmail("xiaomin@sina.com");
            user.setAge(20);
            
            SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd");
            user.setBirthday(dateformat.parse("1996-10-01"));        
            
            /**
             * ObjectMapper是JSON操作的核心,Jackson的所有JSON操作都是在ObjectMapper中实现。
             * ObjectMapper有多个JSON序列化的方法,可以把JSON字符串保存File、OutputStream等不同的介质中。
             * writeValue(File arg0, Object arg1)把arg1转成json序列,并保存到arg0文件中。
             * writeValue(OutputStream arg0, Object arg1)把arg1转成json序列,并保存到arg0输出流中。
             * writeValueAsBytes(Object arg0)把arg0转成json序列,并把结果输出成字节数组。
             * writeValueAsString(Object arg0)把arg0转成json序列,并把结果输出成字符串。
             */
            ObjectMapper mapper = new ObjectMapper();
            
            //User类转JSON
            //输出结果:{"name":"小民","age":20,"birthday":844099200000,"email":"xiaomin@sina.com"}
            String json = mapper.writeValueAsString(user);
            System.out.println(json);
            
            //Java集合转JSON
            //输出结果:[{"name":"小民","age":20,"birthday":844099200000,"email":"xiaomin@sina.com"}]
            List<User> users = new ArrayList<User>();
            users.add(user);
            String jsonlist = mapper.writeValueAsString(users);
            System.out.println(jsonlist);
        }
    }

      ObjectMapper是JSON操作的核心,Jackson的所有JSON操作都是在ObjectMapper中实现。

      ObjectMapper有多个JSON序列化的方法,可以把JSON字符串保存File、OutputStream等不同的介质中。

    (1)writeValue(File arg0, Object arg1)把arg1转成json序列,并保存到arg0文件中。

    (2)writeValue(OutputStream arg0, Object arg1)把arg1转成json序列,并保存到arg0输出流中。

    (3)writeValueAsBytes(Object arg0)把arg0转成json序列,并把结果输出成字节数组。

    (4)writeValueAsString(Object arg0)把arg0转成json序列,并把结果输出成字符串。

    4、JSON反序列化 —— JSON转Java类

    import java.io.IOException;
    import java.text.ParseException;
    import com.fasterxml.jackson.databind.ObjectMapper;
     
    public class JacksonDemo {
        public static void main(String[] args) throws ParseException, IOException {
            String json = "{"name":"小民","age":20,"birthday":844099200000,"email":"xiaomin@sina.com"}";
            
            /**
             * ObjectMapper支持从byte[]、File、InputStream、字符串等数据的JSON反序列化。
             */
            ObjectMapper mapper = new ObjectMapper();
            User user = mapper.readValue(json, User.class);
            System.out.println(user);
        }
    }

      ObjectMapper支持从byte[]、File、InputStream、字符串等数据的JSON反序列化。主要采用的就是 readValue() 方法。

    5、Jackson 注解

      Jackson提供了一系列注解,方便对JSON序列化和反序列化进行控制,下面介绍一些常用的注解。

    @JsonIgnore 此注解用于属性上,作用是进行JSON操作时忽略该属性。

    @JsonFormat 此注解用于属性上,作用是把Date类型直接转化为想要的格式,如@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss")。

    @JsonProperty 此注解用于属性上,作用是把该属性的名称序列化为另外一个名称,如把trueName属性序列化为name,@JsonProperty("name")。

    // 比如我们常用的时间格式化注解,就是这个 jackson 里的啦
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh", timezone = "GMT+8")
    private Date createTime;
    // 不JSON序列化年龄属性
    @JsonIgnore 
    private Integer age;
    
    // 序列化email属性为mail
    @JsonProperty("mail")
    private String email;

    6、自定义配置文件

    #jackson
    #日期格式化
    spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
    #spring.jackson.date-format=yyyy-MM-dd
    #格式化输出 spring.jackson.serialization.indent_output=true
    #忽略无法转换的对象 spring.jackson.serialization.fail_on_empty_beans=false
    #设置空如何序列化 spring.jackson.defaultPropertyInclusion=NON_EMPTY
    #允许对象忽略json中不存在的属性 spring.jackson.deserialization.fail_on_unknown_properties=false
    #允许出现特殊字符和转义符 spring.jackson.parser.allow_unquoted_control_chars=true
    #允许出现单引号 spring.jackson.parser.allow_single_quotes=true

      加了这个配置,spring.jackson.date-format=yyyy-MM-dd HH:mm:ss,我们就不需要再在实体类里去加这样的注解了。

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh", timezone = "GMT+8")
    private Date createTime;

      注意时区是必须要加的,上面配置没有加时区

    #jackson相关配置
    spring.jackson.date-format = yyyy-MM-dd HH:mm:ss
    #时区必须要设置 spring.jackson.time-zone= GMT+8
    #ALWAYS的意思是即时属性为null,仍然也会输出这个key spring.jackson.default-property-inclusion=ALWAYS

      yml形式

    spring:
        jackson:
           #参数意义:
           #JsonInclude.Include.ALWAYS              默认
           #JsonInclude.Include.NON_DEFAULT     属性为默认值不序列化
           #JsonInclude.Include.NON_EMPTY         属性为 空(””) 或者为 NULL 都不序列化
           #JsonInclude.Include.NON_NULL           属性为NULL   不序列化
           default-property-inclusion: ALWAYS
           time-zone: GMT+8
           date-format: yyyy-MM-dd HH:mm:ss

    7、创建bean、及在配置类中修改属性,可以看这篇博客:https://blog.csdn.net/weixin_38413579/article/details/82562634

    三、继续解决方案

      然后我们继续看问题的解决方案。

    1、第一种解决方案

      ObjectMapper 对象添加:mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

    String s = "{"id":1,"name":"test","age":19}";
    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    User value = mapper.readValue(s, User.class);
    System.out.println(value);

    2、第二种解决方案

      在需要转化的对象的类中添加注解,注解信息如下

    @JsonIgnoreProperties(ignoreUnknown = true)
    public class User{
         ......
    }

    3、第三种解决方案,就是上面的在实体类上加上对应的字段

  • 相关阅读:
    29. Divide Two Integers
    leetCode 17. Letter Combinations of a Phone Number
    查找
    快速排序
    希尔排序
    插入排序
    归并排序,还有非递归方式没写
    堆排序--还有递归法没有写
    c++实现字符串全排序
    归并排序
  • 原文地址:https://www.cnblogs.com/goloving/p/14921674.html
Copyright © 2011-2022 走看看