分享几个在项目中经常用到的工具类

目录

前言

1、String工具类

2、File工具类

3、接口资源扫描工具类

4、SQL脚本格式化工具类

5、ip地址工具类

6、文件上传工具类

7、获取用户登录信息的工具类


前言

我们在进行项目开发的时候可能会经常用到一些字符串相关的操作,然后可能产生大量冗余的代码,这时候可以把我们用到的操作提取出来,放到一个单独的工具类里,比如命名为StringUtils,这个工具类里的方法几乎可以涵盖我们日常所需,接下来,我将个人的几个工具类分享给大家。

1、String工具类

import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * String工具类
 * @author heyunlin
 * @version 1.0
 */
public class StringUtils {
    
    /**
     * 判断字符串是否为null或""
     * 字符串为""或null返回true,否则返回false
     * @param str 要判断的字符串
     * @return boolean
     */
    public static boolean isEmpty(String str) {
        return isNullOrEmpty(str);
    }

    /**
     * 判断字符串是否为""或null
     * 字符串为""或null返回false,否则返回true
     * @param str 要判断的字符串
     * @return boolean
     */
    public static boolean isNotEmpty(String str) {
        return !isEmpty(str);
    }

    /**
     * 判断字符串是否为空白字符
     * 字符串为空白字符返回true,否则返回false
     * @param str 要判断的字符串
     * @return boolean
     */
    public static boolean isBlank(String str) {
        return str.trim().length() == 0;
    }

    /**
     * 判断字符串是不是空白字符
     * 字符串不是空白字符返回true,否则返回false
     * @param str 要判断的字符串
     * @return boolean
     */
    public static boolean isNotBlank(String str) {
        return !isBlank(str);
    }

    /**
     * 判断字符串是否为null或""
     * 字符串为""或null返回true,否则返回false
     * @param str 要判断的字符串
     * @return boolean
     */
    public static boolean isNullOrEmpty(String str) {
        return str == null || str.isEmpty();
    }

    /**
     * 检查字符串是否包含空白字符
     * 如果不包含空格返回true,否则返回false
     * @param str 需要比较的字符串
     * @return boolean
     */
    public static boolean check(String str) {
        // 去除空白字符后字符串的长度
        int realLength = str.replaceAll("\\s", "").length();
        // 字符串原来的长度
        int originalLength = str.length();

        return realLength == originalLength;
    }

    /**
     * 根据当前时间生成UUID
     * @return String
     */
    public static String uuid() {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        LocalDateTime localDate = LocalDateTime.now();

        return localDate.format(formatter);
    }

    /**
     * 通过文件名获取文件类型
     * @param fileName 文件名
     */
    public static String getFileType(String fileName) {
        // 得到文件名中最后一次出现"."的位置
        int index = fileName.lastIndexOf('.');

        // 文件类型统一转换为小写
        return fileName.substring(index).toLowerCase();
    }

    /**
     * 获取文件名
     * @param filename String
     * @return String 由当前时间生成的新文件名
     */
    public static String getFileName(String filename) {
        // 返回uuid.文件类型,如:20220618131456.jpg
        return uuid() + getFileType(filename);
    }

    /**
     * 获取文件名
     * @param file MultipartFile对象
     * @return String 由当前时间生成的新文件名
     */
    public static String getFileName(MultipartFile file) {
        // 得到上传文件的原始文件名
        String filename = file.getOriginalFilename();

        // 判断文件名是否为空
        if (isNullOrEmpty(filename)) {
            throw new RuntimeException("获取文件名失败!");
        }

        // 返回uuid.文件类型,如:20220618131456.jpg
        return uuid() + getFileType(filename);
    }

    /**
     * 驼峰命名转下划线命名
     * @param str 待转换的字符串
     * @return String
     */
    public static String toLowerCase(String str) {
        // 小写和大写紧挨一起的地方加上分隔符_,然后全部转为小写
        str = str.replaceAll("([a-z])([A-Z])", "$1_$2");

        return str.toLowerCase();
    }

    /**
     * 下划线命名转驼峰命名
     * @param str 待转换的字符串
     * @return String
     */
    private static String toUpperCase(String str) {
        // 将下划线替换为空格
        StringBuilder under= new StringBuilder();
        str = str.toLowerCase().replace("_", " ");

        // 将字符串根据空格分割成数组
        String[] array = str.split(" ");

        // 将每个单词首字母大写
        for (String s : array) {
            String letter = s.substring(0, 1).toUpperCase() + s.substring(1);

            under.append(letter);
        }

        return under.toString();
    }

}

2、File工具类

package cn.edu.sgu.www.mhxysy.util;

import lombok.extern.slf4j.Slf4j;

import java.io.File;

/**
 *	File工具类
 * @author heyunlin
 * @version 1.0
 */
@Slf4j
public class FileUtils {

	/**
	 * 创建文件夹
	 * @param name 文件夹名
	 */
	public static void createFolder(String name) {
		File file = new File(name);
		
		if(file.exists()) {
			log.debug("文件夹{}已存在···", name);
		} else {
			boolean result = file.mkdirs();

			log.debug(("创建文件夹{}" + (result ? "成功": "失败") + ":"), name);
		}
	}
	
	/**
	 * 删除文件,可以是文件或文件夹
	 * @param fileName 要删除的文件名
	 * @return 删除成功返回true,否则返回false
	 */
	public static boolean delete(String fileName) {
		File file = new File(fileName);
		
		if (!file.exists()) {
			log.debug("删除文件失败:{}不存在!", fileName);

			return false;
		} else {
			if (file.isFile()) {
				return deleteFile(fileName);
			} else {
				return deleteDirectory(fileName);
			}
		}
	}

	/**
	 * 删除单个文件
	 * @param fileName 要删除的文件的文件名
	 * @return 单个文件删除成功返回true,否则返回false
	 */
	public static boolean deleteFile(String fileName) {
		File file = new File(fileName);
		
		// 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
		if (file.exists() && file.isFile()) {
			if (file.delete()) {
				log.debug("成功删除文件:{}", fileName);
				
				return true;
			} else {
				log.debug("删除文件{}失败!", fileName);

				return false;
			}
		} else {
			log.debug("删除文件失败!文件{}不存在!", fileName);
			
			return false;
		}
	}

	/**
	 * 删除目录及目录下的文件
	 * @param dir 要删除的目录的文件路径
	 * @return 目录删除成功返回true,否则返回false
	 */
	public static boolean deleteDirectory(String dir) {
		File dirFile = new File(dir);
		
		// 如果dir对应的文件不存在,或者不是一个目录,则退出
		if ((!dirFile.exists()) || (!dirFile.isDirectory())) {
			log.debug("删除目录失败!文件{}不存在!", dir);

			return false;
		}
		
		boolean flag = true;
		
		// 删除文件夹中的所有文件包括子目录
		File[] files = dirFile.listFiles();

		assert files != null;
		for (File file : files) {
			// 删除子文件
			if (file.isFile()) {
				flag = FileUtils.deleteFile(file.getAbsolutePath());

				if (!flag)
					break;
			}

			// 删除子目录
			else if (file.isDirectory()) {
				flag = FileUtils.deleteDirectory(file.getAbsolutePath());

				if (!flag)
					break;
			}
		}
		
		if (!flag) {
			log.debug("删除目录失败!");
			
			return false;
		}
		
		// 删除当前目录
		if (dirFile.delete()) {
			log.debug("删除目录{}成功!", dir);

			return true;
		} else {
			return false;
		}
	}

}

3、接口资源扫描工具类

这个工具类用于扫描项目中的Controller接口,扫描到的接口数据保存到数据库中,可以用来实现接口鉴权。

package cn.edu.sgu.www.mhxysy.util;

import cn.edu.sgu.www.mhxysy.MhxysyApplication;
import cn.edu.sgu.www.mhxysy.entity.system.Permission;
import cn.edu.sgu.www.mhxysy.enums.RequestMethod;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 接口资源扫描工具类
 * @author heyunlin
 * @version 1.0
 */
@Component
public class ResourceScanner {
    /**
     * 服务名
     */
    @Value("${spring.application.name}")
    private String SERVICE_NAME;
    
    private static List<String> classPaths = new ArrayList<>();
    private static final List<Permission> resources = new ArrayList<>();
    
    public List<Permission> scan(String basePackage) throws ClassNotFoundException {
        // 删除掉上一次的数据
        if (!resources.isEmpty()) {
            resources.clear();
        }
        if (!classPaths.isEmpty()) {
            classPaths.clear();
        }
        
        String classpath = MhxysyApplication.class.getResource("/").getPath().replaceFirst("/", "");
        String searchPath = classpath + basePackage.replace(".", "/");
        searchPath = searchPath.replace("test-classes", "classes");
        classPaths = doPath(new File(searchPath));

        for(String classPath : classPaths) {
            classPath = classPath.replace(classpath.replace("/", "\\")
                    .replaceFirst("\\\\", ""), "")
                    .replace("\\", ".")
                    .replace(".class", "");
            classpath = classPath.substring(classPath.indexOf(basePackage));
            Class<?> cls = Class.forName(classpath);
            RequestMapping requestMapping = cls.getAnnotation(RequestMapping.class);

            // 判断多种注解的情况
            String prefix = "";
            Permission parent = new Permission();

            if(requestMapping != null) {
                // path或者value
                prefix = requestMapping.value().length > 0 ? requestMapping.value()[0] : requestMapping.path()[0];

                parent.setId(SERVICE_NAME + "_" + cls.getSimpleName());
                parent.setType(0);
                parent.setUrl(prefix);

                // 设置value
                if (cls.isAnnotationPresent(Api.class)) {
                    Api api = cls.getAnnotation(Api.class);

                    if (api != null) {
                        String name = api.tags()[0];

                        // 类的接口文档@Api注解的值以“控制器”或“控制器类”结束
                        parent.setName(name.substring(0, name.indexOf("控制器")).concat("管理"));
                    }
                }

                resources.add(parent);
            }
            Method[] methods = cls.getDeclaredMethods();

            for (Method value : methods) {
                getClassAnnotation(value, prefix, cls, parent.getId());
            }
        }

        return resources;
    }

    /**
     * 得到类上面的注解信息
     * @param method Method
     * @param prefix String
     * @param cls Class<?>
     * @param parentId String
     */
    public void getClassAnnotation(Method method, String prefix, Class<?> cls, String parentId) {
        String url = null;
        Permission permission = new Permission();

        if (method.isAnnotationPresent(RequestMapping.class)) {
            RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
            url = prefix + (requestMapping.value().length > 0 ? requestMapping.value()[0] : requestMapping.path()[0]);
            String requestMethod = requestMapping.method().length > 0 ? requestMapping.method()[0].name() : "get";

            permission.setMethod(RequestMethod.getValueByName(requestMethod));
        } else if (method.isAnnotationPresent(GetMapping.class)) {
            GetMapping getMapping = method.getAnnotation(GetMapping.class);
            url = prefix + getMapping.value()[0];

            permission.setMethod(RequestMethod.GET.getValue());
        } else if (method.isAnnotationPresent(PostMapping.class)) {
            PostMapping postMapping = method.getAnnotation(PostMapping.class);
            url = prefix + postMapping.value()[0];

            permission.setMethod(RequestMethod.POST.getValue());
        }

        // 处理URL
        if(url != null && url.endsWith("/")) {
            url = url.substring(0, url.length() - 1);
        }
        permission.setUrl(url);

        // 设置value
        if (method.isAnnotationPresent(ApiOperation.class)) {
            ApiOperation operation = method.getAnnotation(ApiOperation.class);

            if (operation != null) {
                String name = operation.value();

                permission.setName(name);
            }
        }

        permission.setType(1);
        permission.setService("mhxysy");
        permission.setParentId(parentId);
        permission.setId(SERVICE_NAME + "_" + cls.getSimpleName() + "_" + method.getName());

        resources.add(permission);
    }

    private List<String> doPath(File file) {
        if (file.isDirectory()) {
            File[] files = file.listFiles();

            if (files != null) {
                for (File f1 : files) {
                    doPath(f1);
                }
            }
        } else {
            if (file.getName().endsWith(".class")) {
                classPaths.add(file.getPath());
            }
        }

        return classPaths;
    }

}

 Permission.java

package cn.edu.sgu.www.mhxysy.entity.system;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;

/**
 * 权限表
 * @author heyunlin
 * @version 1.0
 */
@Data
@TableName("permission")
public class Permission implements Serializable {
    private static final long serialVersionUID = 18L;

    @TableId(value = "id", type = IdType.INPUT)
    private String id;

    /**
     * 权限名称
     */
    private String name;

    /**
     * 类型
     *  0-顶级权限(控制器类)
     *  1-子级权限(接口方法)
     */
    private Integer type;

    /**
     * 请求路径
     */
    private String url;

    /**
     * 请求方式:0-get;1-post
     */
    private Integer method;

    /**
     * 服务名
     */
    private String service;

    /**
     * 父级权限id
     */
    private String parentId;
}

4、SQL脚本格式化工具类

该工具类用于将从mysql数据库导出的sql脚本格式化,让自增的ID替换为null,只需要调整一下sql语句的顺序之后就可以实现ID从1自增了(在这之前执行truncate语句重置表,注意:一定先备份表的数据再执行truncate)

package cn.edu.sgu.www.mhxysy.util;

import java.io.*;

/**
 * 该类用于修改sql文件,把导出的sql脚本中values后面的id值替换为null
 * truncate表之后重新执行生成的sql文件即可以实现表数据从1开始自动排序
 * // 注意,SQL文件应该只包含sql的insert语句,多余的其他语句要全部删除
 * @author heyunlin
 * @version 1.0
 */
public class SqlResortUtil {

    public static void main(String[] args) throws IOException {
        InputStream fis = new FileInputStream("src/test.sql");
        InputStream bis = new BufferedInputStream(fis);
        InputStreamReader isr = new InputStreamReader(bis);
        BufferedReader br = new BufferedReader(isr);

        String line;
        OutputStream fos = new FileOutputStream("src/test-cp.sql");
        PrintWriter writer = new PrintWriter(fos);

        while((line = br.readLine()) != null) {
            int start = line.indexOf("(");
            int end = line.indexOf(",");

            String data = line.substring(0, start + 1) + "null" + line.substring(end);

            writer.println(data);
            writer.flush();
        }

        br.close();
        fos.close();
    }

}

 sql脚本的内容应该是这种格式

insert into 数据库名.表名 values (编号, 字段1的值, 字段2的值, ...);

例如:

INSERT INTO `mhxysy`.`prop_category` VALUES (1, '珍品宠物', 0, NULL, NULL, 'chongwu', 100);
INSERT INTO `mhxysy`.`prop_category` VALUES (2, '珍品装备', 0, NULL, NULL, 'equipment', 200);
INSERT INTO `mhxysy`.`prop_category` VALUES (3, '器灵', 0, NULL, NULL, 'qiling', 300);
INSERT INTO `mhxysy`.`prop_category` VALUES (4, '装备打造', 0, NULL, NULL, NULL, 400);
INSERT INTO `mhxysy`.`prop_category` VALUES (5, '星印', 0, NULL, NULL, 'xingyin', 500);
INSERT INTO `mhxysy`.`prop_category` VALUES (6, '宠物装备', 0, NULL, NULL, NULL, 600);
INSERT INTO `mhxysy`.`prop_category` VALUES (7, '高级兽决', 0, NULL, NULL, 'msyj', 700);
INSERT INTO `mhxysy`.`prop_category` VALUES (8, '低级兽决', 0, NULL, NULL, 'msyj', 800);
INSERT INTO `mhxysy`.`prop_category` VALUES (9, '药品', 0, NULL, NULL, 'medicine', 900);
INSERT INTO `mhxysy`.`prop_category` VALUES (10, '烹饪', 0, NULL, NULL, 'cuisine', 1000);

 

5、ip地址工具类

package cn.edu.sgu.www.mhxysy.util;

import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * ip地址工具类
 * @author heyunlin
 * @version 1.0
 */
public class IpUtils {

    /**
     * 获取本机IP地址
     */
    public static String getLocalHostAddress() {
        InetAddress inetAddress = null;

        try {
            inetAddress = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }

        return inetAddress == null ? null : inetAddress.getHostAddress();
    }

    /**
     * 获取本机名称
     */
    public static String getLocalHostName() {
        InetAddress inetAddress = null;

        try {
            inetAddress = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }

        return inetAddress == null ? null : inetAddress.getHostName();
    }

    /**
     * 获取客户端IP
     * @return String
     */
    public static String getIp() {
        HttpServletRequest request = getRequest();
        String ip = request.getHeader("x-forwarded-for");

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }

        return ip;
    }

    /**
     * 获取浏览器类型
     * @param request HttpServletRequest
     * @return String 浏览器类型
     */
    public static String getBrowserType(HttpServletRequest request) {
        String type = "其它";
        String browserName = request.getHeader("USER-AGENT").toLowerCase();

        if (browserName.indexOf("msie") > 0) {
            type = "IE";
        } else if (browserName.indexOf("firefox") > 0) {
            type = "Firefox";
        } else if (browserName.indexOf("chrome") > 0) {
            type = "Chrome";
        } else if (browserName.indexOf("opera") > 0) {
            type = "Opera";
        } else if (browserName.indexOf("gecko") > 0 && browserName.indexOf("rv:11") > 0) {
            type = "IE11";
        }

        return type;
    }

    private static HttpServletRequest getRequest() {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();

        assert attributes != null;
        return ((ServletRequestAttributes) attributes).getRequest();
    }

    public static void main(String[] args) throws UnknownHostException {
        InetAddress inetAddress = InetAddress.getLocalHost();

        // 本机IP地址
        System.out.println("Local HostAddress:" + inetAddress.getHostAddress());
        // 本机名称
        System.out.println("Local host name: " + inetAddress.getHostName());
    }

}

6、文件上传工具类

UploadUtils封装了本地文件上传的通用代码:

1、通过MultipartFile对象获取文件名

2、创建目标文件对象

3、保存文件

4、返回文件的相对路径,主要用于前端的图片回显

package cn.edu.sgu.www.mhxysy.util;

import cn.edu.sgu.www.mhxysy.restful.ResponseCode;
import cn.edu.sgu.www.mhxysy.exception.GlobalException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

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

/**
 * 文件上传工具类
 * @author heyunlin
 * @version 1.0
 */
@Component
public class UploadUtils {
    /**
     * 文件上传根路径
     */
    @Value("${uploads.path}")
    private String root;

    /**
     * 图片文件名后缀
     */
    @Value("${uploads.file.suffix}")
    String picSuffix;

    public String getRoot() {
        return root;
    }

    /**
     * 图片上传
     * @param file MultipartFile对象
     * @param directory 文件上传目录
     * @return String 图片的相对路径
     */
    public String upload(MultipartFile file, String directory) throws IOException {
        boolean result = check(file);

        if (result) {
            // 获取文件名
            String fileName = StringUtils.getFileName(file);
            // 创建目标对象
            File targetFile = new File(root + directory, fileName);

            // 保存文件
            file.transferTo(targetFile);

            return directory + "/" + fileName;
        }

        return null;
    }

    /**
     * 检查文件格式
     * @param file MultipartFile
     */
    private boolean check(MultipartFile file) {
        if (file == null) {
            throw new GlobalException(ResponseCode.BAD_REQUEST, "您未上传任何图片!");
        }

        String filename = file.getOriginalFilename();

        if (StringUtils.isNotEmpty(filename)) {
            String fileType = StringUtils.getFileType(filename).toLowerCase();

            if (!picSuffix.contains(fileType)) {
                throw new GlobalException(ResponseCode.BAD_REQUEST, "只允许上传格式为" + picSuffix + "的图片");
            }

            return true;
        } else {
            throw new GlobalException(ResponseCode.BAD_REQUEST, "获取上传的文件名失败~");
        }
    }

}

application.yml相关的配置,可以配置文件上传的路径,也就是静态资源路径,以及接受的文件类型

uploads:
  # 文件上传路径
  path: D:/uploads/mhxysy
  # 上传文件的类型(文件名后缀)
  file:
    suffix: .webp,.jpeg,.jpg,.png

7、获取用户登录信息的工具类

该工具类仅适用于shiro安全框架

package cn.edu.sgu.www.mhxysy.util;

import cn.edu.sgu.www.mhxysy.restful.ResponseCode;
import cn.edu.sgu.www.mhxysy.entity.system.User;
import cn.edu.sgu.www.mhxysy.exception.GlobalException;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;

/**
 * 获取用户信息的工具类
 * @author heyunlin
 * @version 1.0
 */
public class UserUtils {

    /**
     * 得到Subject对象
     * @return Subject
     */
    public static Subject getSubject() {
        return SecurityUtils.getSubject();
    }

    /**
     * 获取登录的用户信息
     * @return User
     */
    public static User getUserInfo() {
        Object object =  getSubject().getPrincipal();

        if (object == null) {
            throw new GlobalException(ResponseCode.BAD_REQUEST, "获取登录信息失败,当前没有用户登录。");
        }

        return (User) object;
    }

    /**
     * 获取登录的用户名
     * @return String
     */
    public static String getLoginUsername() {
        return getUserInfo().getUsername();
    }

}

User.java

package cn.edu.sgu.www.mhxysy.entity.system;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;

import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * 用户
 * @author heyunlin
 * @version 1.0
 */
@Data
@TableName("user")
public class User implements Serializable {
	private static final long serialVersionUID = 18L;

	@TableId(value = "id", type = IdType.INPUT)
	private String id;

	/**
	 * 姓名
	 */
	private String name;

	/**
	 * 性别
	 */
	private Integer gender;

	/**
	 * 用户名
	 */
	private String username;

	/**
	 * 密码
	 */
	private String password;

	/**
	 * 手机号
	 */
	private String phone;

	/**
	 * 是否启用
	 */
	private Boolean isEnable;

	/**
	 * 最后一次登录时间
	 */
	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
	private LocalDateTime lastLoginTime;
}

好了,这篇文章就分享到这里了,看完不要忘了点赞+收藏哦~