原文网址:SpringBoot--手写常用工具类_IT利刃出鞘的博客-CSDN博客
简介
本文介绍我自己手写的一些SpringBoot的工具类,很好用。
获得SpringContext
说明
可以通过本工具类静态获取ApplicationContext,从而进一步使用ApplicationContext进行处理,比如:从容器中获取bean。
优点
方便快捷,调用者直接使用静态方法即可,调用者无需自己再去实现ApplicationContextAware接口。
相关网址
Spring(SpringBoot)--ApplicationContext--使用/教程/原理_IT利刃出鞘的博客-CSDN博客
代码
package com.knife.common.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class ApplicationContextHolder implements ApplicationContextAware {
    private static ApplicationContext context;
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        ApplicationContextHolder.context = context;
    }
    public static ApplicationContext getContext() {
        return context;
    }
}  用法
- 根据class获得bean 
  - Xxx xxx = ApplicationContextHolder.getContext().getBean(Xxx.class);
 
- 根据名字获得代理后的bean(常用) 
  - Xxx xxx = ApplicationContextHolder.getContext().getBean("userService");
 
- 根据名字获得未代理的bean(即FactoryBean)(不常用) 
  - Xxx xxx = ApplicationContextHolder.getContext().getBean("&userService");
 
Json转换
说明
本工具是对Jackson(也就是ObjectMapper)的封装。
优点
- 调用者无需捕获异常 
  - 本工具捕获了checked 异常,然后抛出RuntimeException,所以无需外部捕获
 
- 缺陷少 
  - 本文基于Jackson,没有FastJson那么多bug
 
相关网址
Jackson--使用/教程/示例_IT利刃出鞘的博客-CSDN博客_jackson教程
代码
package com.knife.common.util;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;
import java.util.Map;
/**
 * Json工具
 */
public class JsonUtil {
    private static final ObjectMapper objectMapper = new ObjectMapper();
    static {
        // 反序列化:JSON字段中有Java对象中没有的字段时不报错
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 反序列化:不允许基本类型为null
        //objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);
        // 序列化:序列化BigDecimal时不使用科学计数法输出
        objectMapper.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true);
        // 序列化:Java对象为空的字段不拼接JSON
        //objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    }
    public static <T> T getObjectFromString(String string, Class<T> cls) {
        try {
            return objectMapper.readValue(string, cls);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
    @SuppressWarnings("rawtypes")
    public static Map getMapFromString(String str) {
        try {
            return objectMapper.readValue(str, Map.class);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
    public static <T> T getMapFromString(String str, TypeReference<T> valueTypeRef) {
        try {
            return objectMapper.readValue(str, valueTypeRef);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
    public static String getStringFromObject(Object obj) {
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
    public static <T> List<T> getObjectListFromString(String string, TypeReference<List<T>> typeReference) {
        try {
            return objectMapper.readValue(string, typeReference);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public static JsonNode getTreeFromString(String string) {
        try {
            return objectMapper.readTree(string);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
}
用法
跟ObjectMapper一样。例如:User user = JsonUtil.getObjectFromString(str, User.class);
获得空值属性名
说明
可以获得某个对象中值为空(为null或者空字符串等)的属性名,然后可以用于作为BeanUtils.copyProperties的最后一个参数,不拷贝这些空的属性。
优点
方便快捷。
相关网址
Spring--BeanUtils忽略空值拷贝--方法/实例_IT利刃出鞘的博客-CSDN博客_bean拷贝忽略空值
代码
package com.example.util;
 
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
 
import java.beans.PropertyDescriptor;
import java.util.HashSet;
import java.util.Set;
 
public class PropertyUtil {
    public static String[] getNullPropertyNames(Object source) {
        BeanWrapper src = new BeanWrapperImpl(source);
        PropertyDescriptor[] pds = src.getPropertyDescriptors();
 
        Set<String> emptyNames = new HashSet<>();
 
        for (PropertyDescriptor pd : pds) {
            //check if value of this property is null then add it to the collection
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null){
                emptyNames.add(pd.getName());
            }
        }
 
        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }
}用法
package com.example.controller;
 
import com.example.entity.Blog;
import com.example.entity.User;
import com.example.util.PropertyUtil;
import com.example.vo.BlogRequest;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
 
import java.time.LocalDateTime;
import java.util.Arrays;
 
@RestController
public class HelloController {
    @Autowired
    private ObjectMapper objectMapper;
 
    @GetMapping("/test")
    public String test() {
        BlogRequest blogRequest = new BlogRequest();
        blogRequest.setId(10L);
        blogRequest.setTitle("Java实战");
        // blogRequest.setContent("本文介绍获取null的字段名的方法");
        blogRequest.setUser(new User());
        blogRequest.setCreateTime(LocalDateTime.now());
        // blogRequest.setCreateTime(LocalDateTime.now());
        blogRequest.setDeletedFlag(0L);
 
        User user = new User();
        user.setId(15L);
        user.setUserName("Tony");
        // user.setNickName("Iron Man");
        // user.setStatus(1);
 
        String[] nullPropertyNames = PropertyUtil.getNullPropertyNames(blogRequest);
        System.out.println(Arrays.toString(nullPropertyNames));
 
        System.out.println("------------------------------");
        Blog blog = new Blog();
        BeanUtils.copyProperties(blogRequest, blog, nullPropertyNames);
 
        try {
            System.out.println(objectMapper.writeValueAsString(blog));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
 
        return "test success";
    }
}获取异常的堆栈信息
说明
本工具类可以打印详细的异常堆栈的信息。
比如:在抛出NullPointException时,message是这样的:java.lang.NullPointException。用本工具可以获得方法的调用流程,方便排查问题。
优点
异常信息很详细
代码
package com.knife.common.util;
/**
 * 异常工具类
 */
public class ThrowableUtil {
    /**
     * 获取以指定包名为前缀的堆栈信息
     *
     * @param e             异常
     * @return 堆栈信息
     */
    public static String getStackTrace(Throwable e) {
        StringBuilder s = new StringBuilder().append(e);
        for (StackTraceElement traceElement : e.getStackTrace()) {
            s.append("    at ").append(traceElement);
        }
        return s.toString();
    }
    /**
     * 获取以指定包名为前缀的堆栈信息
     *
     * @param e             异常
     * @param packagePrefix 包前缀
     * @return 堆栈信息
     */
    public static String getStackTraceByPackage(Throwable e, String packagePrefix) {
        StringBuilder s = new StringBuilder().append(e);
        for (StackTraceElement traceElement : e.getStackTrace()) {
            if (!traceElement.getClassName().startsWith(packagePrefix)) {
                break;
            }
            s.append("    at ").append(traceElement);
        }
        return s.toString();
    }
    /**
     * 获取最后n条堆栈信息
     * @param e 异常对象
     * @param n 最后n条
     * @return 错误信息
     */
    public static String getLastStackTrace(Throwable e, Integer n) {
        Integer lineNumber = n;
        if (lineNumber == null) {
            lineNumber = 10;
        }
        StringBuilder s = new StringBuilder().append(e);
        int i = 0;
        for (StackTraceElement traceElement : e.getStackTrace()) {
            s.append("    at ").append(traceElement);
            if (i >= lineNumber) {
                break;
            }
            i++;
        }
        return s.toString();
    }
}
用法
try{
    ...
} catch(Exception e) {
    log.error(ThrowableUtil.getLastStackTrace(e, 10));
}字段校验
说明
本工具可以手动对@NotBlank、@NotNull等字段进行校验。
使用场景:controller接口的入参很多,需要他人提供,但他人提供的类的字段很多,字段都没有加@NotNull等注解;而且这个类以后很可能再变动。
解决方案:写一个中间类,将入参转换为中间类,在中间类的字段上加@NotBlank等注解,然后用本工具手动校验它。
优点
利用@NotBlank等校验,方便快捷
相关网址
SpringBoot--用hibernate validator手动校验--方法/实例_IT利刃出鞘的博客-CSDN博客_springboot 手动校验
代码
package com.knife.common.util;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.ValidationException;
import javax.validation.Validator;
import java.util.Set;
/**
 * hibernate validator的校验工具
 */
public class ValidateUtil {
    private static final Validator validator =
            Validation.buildDefaultValidatorFactory().getValidator();
    /**
     * 校验实体类
     */
    public static <T> void validate(T t) {
        Set<ConstraintViolation<T>> constraintViolations = validator.validate(t);
        if (constraintViolations.size() > 0) {
            StringBuilder validateError = new StringBuilder();
            for (ConstraintViolation<T> constraintViolation : constraintViolations) {
                validateError.append(constraintViolation.getMessage()).append(";");
            }
            throw new ValidationException(validateError.toString());
        }
    }
    /**
     * 通过组来校验实体类
     */
    public static <T> void validate(T t, Class<?>... groups) {
        Set<ConstraintViolation<T>> constraintViolations = validator.validate(t, groups);
        if (constraintViolations.size() > 0) {
            StringBuilder validateError = new StringBuilder();
            for (ConstraintViolation<T> constraintViolation : constraintViolations) {
                validateError.append(constraintViolation.getMessage()).append(";");
            }
            throw new ValidationException(validateError.toString());
        }
    }
}
用法
User user = new User();
//对user字段赋值
ValidateUtil.validate(user);









