add /GlobalCustomFormat

This commit is contained in:
Looly
2021-06-26 01:47:16 +08:00
parent 85e9bc11c2
commit 613b6f3ac5
16 changed files with 270 additions and 41 deletions

View File

@@ -3,7 +3,7 @@
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
# 5.7.3 (2021-06-25) # 5.7.3 (2021-06-26)
### 🐣新特性 ### 🐣新特性
* 【core 】 增加Convert.toSet方法issue#I3XFG2@Gitee * 【core 】 增加Convert.toSet方法issue#I3XFG2@Gitee
@@ -11,6 +11,8 @@
* 【core 】 新增JAXBUtilpr#346@Gitee * 【core 】 新增JAXBUtilpr#346@Gitee
* 【poi 】 ExcelWriter新增setColumnStyleIfHasData和setRowStyleIfHasDatapr#347@Gitee * 【poi 】 ExcelWriter新增setColumnStyleIfHasData和setRowStyleIfHasDatapr#347@Gitee
* 【json 】 用户自定义日期时间格式时,解析也读取此格式 * 【json 】 用户自定义日期时间格式时,解析也读取此格式
* 【core 】 增加可自定义日期格式GlobalCustomFormat
* 【jwt 】 JWT修改默认有序并规定payload日期格式为秒数
### 🐞Bug修复 ### 🐞Bug修复
* 【json 】 修复XML转义字符的问题issue#I3XH09@Gitee * 【json 】 修复XML转义字符的问题issue#I3XH09@Gitee

View File

@@ -3,6 +3,7 @@ package cn.hutool.core.date;
import cn.hutool.core.comparator.CompareUtil; import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.convert.NumberChineseFormatter; import cn.hutool.core.convert.NumberChineseFormatter;
import cn.hutool.core.date.format.FastDateParser; import cn.hutool.core.date.format.FastDateParser;
import cn.hutool.core.date.format.GlobalCustomFormat;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
@@ -654,6 +655,15 @@ public class CalendarUtil {
calendar.setLenient(lenient); calendar.setLenient(lenient);
for (final String parsePattern : parsePatterns) { for (final String parsePattern : parsePatterns) {
if(GlobalCustomFormat.isCustomFormat(parsePattern)){
final Date parse = GlobalCustomFormat.parse(str, parsePattern);
if(null == parse){
continue;
}
calendar.setTime(parse);
return calendar;
}
final FastDateParser fdp = new FastDateParser(parsePattern, tz, lcl); final FastDateParser fdp = new FastDateParser(parsePattern, tz, lcl);
calendar.clear(); calendar.clear();
try { try {

View File

@@ -3,6 +3,7 @@ package cn.hutool.core.date;
import cn.hutool.core.date.format.DateParser; import cn.hutool.core.date.format.DateParser;
import cn.hutool.core.date.format.DatePrinter; import cn.hutool.core.date.format.DatePrinter;
import cn.hutool.core.date.format.FastDateFormat; import cn.hutool.core.date.format.FastDateFormat;
import cn.hutool.core.date.format.GlobalCustomFormat;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
@@ -251,7 +252,9 @@ public class DateTime extends Date {
* @see DatePattern * @see DatePattern
*/ */
public DateTime(CharSequence dateStr, String format) { public DateTime(CharSequence dateStr, String format) {
this(dateStr, DateUtil.newSimpleFormat(format)); this(GlobalCustomFormat.isCustomFormat(format)
? GlobalCustomFormat.parse(dateStr, format)
: parse(dateStr, DateUtil.newSimpleFormat(format)));
} }
/** /**

View File

@@ -5,6 +5,7 @@ import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.date.format.DateParser; import cn.hutool.core.date.format.DateParser;
import cn.hutool.core.date.format.DatePrinter; import cn.hutool.core.date.format.DatePrinter;
import cn.hutool.core.date.format.FastDateFormat; import cn.hutool.core.date.format.FastDateFormat;
import cn.hutool.core.date.format.GlobalCustomFormat;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.PatternPool; import cn.hutool.core.lang.PatternPool;
import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.CharUtil;
@@ -488,6 +489,11 @@ public class DateUtil extends CalendarUtil {
return null; return null;
} }
// 检查自定义格式
if(GlobalCustomFormat.isCustomFormat(format)){
return GlobalCustomFormat.format(date, format);
}
TimeZone timeZone = null; TimeZone timeZone = null;
if (date instanceof DateTime) { if (date instanceof DateTime) {
timeZone = ((DateTime) date).getTimeZone(); timeZone = ((DateTime) date).getTimeZone();
@@ -696,6 +702,10 @@ public class DateUtil extends CalendarUtil {
* @since 4.5.18 * @since 4.5.18
*/ */
public static DateTime parse(CharSequence dateStr, String format, Locale locale) { public static DateTime parse(CharSequence dateStr, String format, Locale locale) {
if(GlobalCustomFormat.isCustomFormat(format)){
// 自定义格式化器忽略Locale
return new DateTime(GlobalCustomFormat.parse(dateStr, format));
}
return new DateTime(dateStr, DateUtil.newSimpleFormat(format, locale, null)); return new DateTime(dateStr, DateUtil.newSimpleFormat(format, locale, null));
} }

View File

@@ -1,5 +1,6 @@
package cn.hutool.core.date; package cn.hutool.core.date;
import cn.hutool.core.date.format.GlobalCustomFormat;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReUtil; import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
@@ -139,7 +140,7 @@ public class LocalDateTimeUtil {
* 毫秒转{@link LocalDateTime},结果会产生时间偏移 * 毫秒转{@link LocalDateTime},结果会产生时间偏移
* *
* @param epochMilli 从1970-01-01T00:00:00Z开始计数的毫秒数 * @param epochMilli 从1970-01-01T00:00:00Z开始计数的毫秒数
* @param timeZone 时区 * @param timeZone 时区
* @return {@link LocalDateTime} * @return {@link LocalDateTime}
*/ */
public static LocalDateTime of(long epochMilli, TimeZone timeZone) { public static LocalDateTime of(long epochMilli, TimeZone timeZone) {
@@ -174,8 +175,8 @@ public class LocalDateTimeUtil {
return null; return null;
} }
if(temporalAccessor instanceof LocalDate){ if (temporalAccessor instanceof LocalDate) {
return ((LocalDate)temporalAccessor).atStartOfDay(); return ((LocalDate) temporalAccessor).atStartOfDay();
} }
return LocalDateTime.of( return LocalDateTime.of(
@@ -201,8 +202,8 @@ public class LocalDateTimeUtil {
return null; return null;
} }
if(temporalAccessor instanceof LocalDateTime){ if (temporalAccessor instanceof LocalDateTime) {
return ((LocalDateTime)temporalAccessor).toLocalDate(); return ((LocalDateTime) temporalAccessor).toLocalDate();
} }
return LocalDate.of( return LocalDate.of(
@@ -215,11 +216,11 @@ public class LocalDateTimeUtil {
/** /**
* 解析日期时间字符串为{@link LocalDateTime}仅支持yyyy-MM-dd'T'HH:mm:ss格式例如2007-12-03T10:15:30 * 解析日期时间字符串为{@link LocalDateTime}仅支持yyyy-MM-dd'T'HH:mm:ss格式例如2007-12-03T10:15:30
* *
* @param text 日期时间字符串 * @param text 日期时间字符串
* @return {@link LocalDateTime} * @return {@link LocalDateTime}
*/ */
public static LocalDateTime parse(CharSequence text) { public static LocalDateTime parse(CharSequence text) {
return parse(text, (DateTimeFormatter)null); return parse(text, (DateTimeFormatter) null);
} }
/** /**
@@ -252,23 +253,27 @@ public class LocalDateTimeUtil {
return null; return null;
} }
if(GlobalCustomFormat.isCustomFormat(format)){
return of(GlobalCustomFormat.parse(text, format));
}
DateTimeFormatter formatter = null; DateTimeFormatter formatter = null;
if(StrUtil.isNotBlank(format)){ if (StrUtil.isNotBlank(format)) {
// 修复yyyyMMddHHmmssSSS格式不能解析的问题 // 修复yyyyMMddHHmmssSSS格式不能解析的问题
// fix issue#1082 // fix issue#1082
//see https://stackoverflow.com/questions/22588051/is-java-time-failing-to-parse-fraction-of-second //see https://stackoverflow.com/questions/22588051/is-java-time-failing-to-parse-fraction-of-second
// jdk8 bug at: https://bugs.openjdk.java.net/browse/JDK-8031085 // jdk8 bug at: https://bugs.openjdk.java.net/browse/JDK-8031085
if(StrUtil.startWithIgnoreEquals(format, DatePattern.PURE_DATETIME_PATTERN)){ if (StrUtil.startWithIgnoreEquals(format, DatePattern.PURE_DATETIME_PATTERN)) {
final String fraction = StrUtil.removePrefix(format, DatePattern.PURE_DATETIME_PATTERN); final String fraction = StrUtil.removePrefix(format, DatePattern.PURE_DATETIME_PATTERN);
if(ReUtil.isMatch("[S]{1,2}", fraction)){ if (ReUtil.isMatch("[S]{1,2}", fraction)) {
//将yyyyMMddHHmmssS、yyyyMMddHHmmssSS的日期统一替换为yyyyMMddHHmmssSSS格式用0补 //将yyyyMMddHHmmssS、yyyyMMddHHmmssSS的日期统一替换为yyyyMMddHHmmssSSS格式用0补
text += StrUtil.repeat('0', 3-fraction.length()); text += StrUtil.repeat('0', 3 - fraction.length());
} }
formatter = new DateTimeFormatterBuilder() formatter = new DateTimeFormatterBuilder()
.appendPattern(DatePattern.PURE_DATETIME_PATTERN) .appendPattern(DatePattern.PURE_DATETIME_PATTERN)
.appendValue(ChronoField.MILLI_OF_SECOND, 3) .appendValue(ChronoField.MILLI_OF_SECOND, 3)
.toFormatter(); .toFormatter();
} else{ } else {
formatter = DateTimeFormatter.ofPattern(format); formatter = DateTimeFormatter.ofPattern(format);
} }
} }
@@ -279,12 +284,12 @@ public class LocalDateTimeUtil {
/** /**
* 解析日期时间字符串为{@link LocalDate}仅支持yyyy-MM-dd'T'HH:mm:ss格式例如2007-12-03T10:15:30 * 解析日期时间字符串为{@link LocalDate}仅支持yyyy-MM-dd'T'HH:mm:ss格式例如2007-12-03T10:15:30
* *
* @param text 日期时间字符串 * @param text 日期时间字符串
* @return {@link LocalDate} * @return {@link LocalDate}
* @since 5.3.10 * @since 5.3.10
*/ */
public static LocalDate parseDate(CharSequence text) { public static LocalDate parseDate(CharSequence text) {
return parseDate(text, (DateTimeFormatter)null); return parseDate(text, (DateTimeFormatter) null);
} }
/** /**
@@ -323,7 +328,7 @@ public class LocalDateTimeUtil {
/** /**
* 格式化日期时间为yyyy-MM-dd HH:mm:ss格式 * 格式化日期时间为yyyy-MM-dd HH:mm:ss格式
* *
* @param time {@link LocalDateTime} * @param time {@link LocalDateTime}
* @return 格式化后的字符串 * @return 格式化后的字符串
* @since 5.3.11 * @since 5.3.11
*/ */
@@ -350,16 +355,13 @@ public class LocalDateTimeUtil {
* @return 格式化后的字符串 * @return 格式化后的字符串
*/ */
public static String format(LocalDateTime time, String format) { public static String format(LocalDateTime time, String format) {
if (null == time) { return TemporalAccessorUtil.format(time, format);
return null;
}
return format(time, DateTimeFormatter.ofPattern(format));
} }
/** /**
* 格式化日期时间为yyyy-MM-dd格式 * 格式化日期时间为yyyy-MM-dd格式
* *
* @param date {@link LocalDate} * @param date {@link LocalDate}
* @return 格式化后的字符串 * @return 格式化后的字符串
* @since 5.3.11 * @since 5.3.11
*/ */
@@ -478,8 +480,8 @@ public class LocalDateTimeUtil {
* *
* @param temporalAccessor Date对象 * @param temporalAccessor Date对象
* @return {@link Instant}对象 * @return {@link Instant}对象
* @since 5.4.1
* @see TemporalAccessorUtil#toEpochMilli(TemporalAccessor) * @see TemporalAccessorUtil#toEpochMilli(TemporalAccessor)
* @since 5.4.1
*/ */
public static long toEpochMilli(TemporalAccessor temporalAccessor) { public static long toEpochMilli(TemporalAccessor temporalAccessor) {
return TemporalAccessorUtil.toEpochMilli(temporalAccessor); return TemporalAccessorUtil.toEpochMilli(temporalAccessor);

View File

@@ -1,5 +1,6 @@
package cn.hutool.core.date; package cn.hutool.core.date;
import cn.hutool.core.date.format.GlobalCustomFormat;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import java.time.Instant; import java.time.Instant;
@@ -83,6 +84,11 @@ public class TemporalAccessorUtil extends TemporalUtil{
return null; return null;
} }
// 检查自定义格式
if(GlobalCustomFormat.isCustomFormat(format)){
return GlobalCustomFormat.format(time, format);
}
final DateTimeFormatter formatter = StrUtil.isBlank(format) final DateTimeFormatter formatter = StrUtil.isBlank(format)
? null : DateTimeFormatter.ofPattern(format); ? null : DateTimeFormatter.ofPattern(format);

View File

@@ -0,0 +1,119 @@
package cn.hutool.core.date.format;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
/**
* 全局自定义格式<br>
* 用于定义用户指定的日期格式和输出日期的关系
*
* @author looly
* @since 5.7.2
*/
public class GlobalCustomFormat {
public static final String FORMAT_SECONDS = "#sss";
public static final String FORMAT_MILLISECONDS = "#SSS";
private static final Map<CharSequence, Function<Date, String>> formatterMap;
private static final Map<CharSequence, Function<CharSequence, Date>> parserMap;
static {
formatterMap = new ConcurrentHashMap<>();
parserMap = new ConcurrentHashMap<>();
// Hutool预设的几种自定义格式
putFormatter(FORMAT_SECONDS, (date) -> String.valueOf(Math.floorDiv(date.getTime(), 1000)));
putParser(FORMAT_SECONDS, (dateStr) -> DateUtil.date(Math.multiplyExact(Long.parseLong(dateStr.toString()), 1000)));
putFormatter(FORMAT_MILLISECONDS, (date) -> String.valueOf(date.getTime()));
putParser(FORMAT_MILLISECONDS, (dateStr) -> DateUtil.date(Long.parseLong(dateStr.toString())));
}
/**
* 加入日期格式化规则
*
* @param format 格式
* @param func 格式化函数
*/
public static void putFormatter(String format, Function<Date, String> func) {
Assert.notNull(format, "Format must be not null !");
Assert.notNull(func, "Function must be not null !");
formatterMap.put(format, func);
}
/**
* 加入日期解析规则
*
* @param format 格式
* @param func 解析函数
*/
public static void putParser(String format, Function<CharSequence, Date> func) {
Assert.notNull(format, "Format must be not null !");
Assert.notNull(func, "Function must be not null !");
parserMap.put(format, func);
}
/**
* 检查指定格式是否为自定义格式
*
* @param format 格式
* @return 是否为自定义格式
*/
public static boolean isCustomFormat(String format) {
return formatterMap.containsKey(format);
}
/**
* 使用自定义格式格式化日期
*
* @param date 日期
* @param format 自定义格式
* @return 格式化后的日期
*/
public static String format(Date date, CharSequence format) {
if (null != formatterMap) {
final Function<Date, String> func = formatterMap.get(format);
if (null != func) {
return func.apply(date);
}
}
return null;
}
/**
* 使用自定义格式格式化日期
*
* @param temporalAccessor 日期
* @param format 自定义格式
* @return 格式化后的日期
*/
public static String format(TemporalAccessor temporalAccessor, CharSequence format) {
return format(DateUtil.date(temporalAccessor), format);
}
/**
* 使用自定义格式解析日期
*
* @param dateStr 日期字符串
* @param format 自定义格式
* @return 格式化后的日期
*/
public static Date parse(CharSequence dateStr, String format) {
if (null != parserMap) {
final Function<CharSequence, Date> func = parserMap.get(format);
if (null != func) {
return func.apply(dateStr);
}
}
return null;
}
}

View File

@@ -62,6 +62,7 @@ public class JAXBUtil {
/** /**
* xml转换成JavaBean * xml转换成JavaBean
* *
* @param <T> Bean类型
* @param xml XML字符串 * @param xml XML字符串
* @param c Bean类型 * @param c Bean类型
* @return bean * @return bean

View File

@@ -72,6 +72,30 @@ public class DateUtilTest {
Assert.assertEquals("00:00:00", formatTime); Assert.assertEquals("00:00:00", formatTime);
} }
@Test
public void formatAndParseCustomTest() {
String dateStr = "2017-03-01";
Date date = DateUtil.parse(dateStr);
String format = DateUtil.format(date, "#sss");
Assert.assertEquals("1488297600", format);
final DateTime parse = DateUtil.parse(format, "#sss");
Assert.assertEquals(date, parse);
}
@Test
public void formatAndParseCustomTest2() {
String dateStr = "2017-03-01";
Date date = DateUtil.parse(dateStr);
String format = DateUtil.format(date, "#SSS");
Assert.assertEquals("1488297600000", format);
final DateTime parse = DateUtil.parse(format, "#SSS");
Assert.assertEquals(date, parse);
}
@Test @Test
public void beginAndEndTest() { public void beginAndEndTest() {
String dateStr = "2017-03-01 00:33:23"; String dateStr = "2017-03-01 00:33:23";
@@ -883,6 +907,6 @@ public class DateUtilTest {
public void parseNotFitTest(){ public void parseNotFitTest(){
//https://github.com/looly/hutool/issues/1332 //https://github.com/looly/hutool/issues/1332
// 在日期格式不匹配的时候,测试是否正常报错 // 在日期格式不匹配的时候,测试是否正常报错
final DateTime parse = DateUtil.parse("2020-12-23", DatePattern.PURE_DATE_PATTERN); DateUtil.parse("2020-12-23", DatePattern.PURE_DATE_PATTERN);
} }
} }

View File

@@ -20,4 +20,15 @@ public class TemporalAccessorUtilTest {
final String format = TemporalAccessorUtil.format(LocalTime.MIN, DatePattern.NORM_DATETIME_PATTERN); final String format = TemporalAccessorUtil.format(LocalTime.MIN, DatePattern.NORM_DATETIME_PATTERN);
Assert.assertEquals(today + " 00:00:00", format); Assert.assertEquals(today + " 00:00:00", format);
} }
@Test
public void formatCustomTest(){
final String today = TemporalAccessorUtil.format(
LocalDate.of(2021, 6, 26), "#sss");
Assert.assertEquals("1624636800", today);
final String today2 = TemporalAccessorUtil.format(
LocalDate.of(2021, 6, 26), "#SSS");
Assert.assertEquals("1624636800000", today2);
}
} }

View File

@@ -3,6 +3,7 @@ package cn.hutool.json;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TemporalAccessorUtil; import cn.hutool.core.date.TemporalAccessorUtil;
import cn.hutool.core.date.format.GlobalCustomFormat;
import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
@@ -167,10 +168,6 @@ final class InternalJSONUtil {
try { try {
if (StrUtil.containsAnyIgnoreCase(string, ".", "e")) { if (StrUtil.containsAnyIgnoreCase(string, ".", "e")) {
// pr#192@GiteeDouble会出现小数精度丢失问题此处使用BigDecimal // pr#192@GiteeDouble会出现小数精度丢失问题此处使用BigDecimal
//double d = Double.parseDouble(string);
//if (false == Double.isInfinite(d) && false == Double.isNaN(d)) {
// return d;
//}
return new BigDecimal(string); return new BigDecimal(string);
} else { } else {
final long myLong = Long.parseLong(string); final long myLong = Long.parseLong(string);
@@ -275,6 +272,12 @@ final class InternalJSONUtil {
} else{ } else{
dateStr = DateUtil.format(Convert.toDate(dateObj), format); dateStr = DateUtil.format(Convert.toDate(dateObj), format);
} }
if(GlobalCustomFormat.FORMAT_SECONDS.equals(format)
|| GlobalCustomFormat.FORMAT_MILLISECONDS.equals(format)){
// Hutool自定义的秒和毫秒表示默认不包装双引号
return dateStr;
}
//用户定义了日期格式 //用户定义了日期格式
return JSONUtil.quote(dateStr); return JSONUtil.quote(dateStr);
} }

View File

@@ -113,21 +113,25 @@ public interface JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K> {
@Override @Override
default Date getDate(K key, Date defaultValue){ default Date getDate(K key, Date defaultValue){
// 默认转换
final Object obj = getObj(key);
if (null == obj) {
return defaultValue;
}
if(obj instanceof Date){
return (Date) obj;
}
String format = OptionalBean.ofNullable(getConfig()).getBean(JSONConfig::getDateFormat).get(); String format = OptionalBean.ofNullable(getConfig()).getBean(JSONConfig::getDateFormat).get();
if(StrUtil.isNotBlank(format)){ if(StrUtil.isNotBlank(format)){
// 用户指定了日期格式,获取日期属性时使用对应格式 // 用户指定了日期格式,获取日期属性时使用对应格式
final String str = getStr(key); final String str = Convert.toStr(obj);
if(null == str){ if(null == str){
return defaultValue; return defaultValue;
} }
return DateUtil.parse(str, format); return DateUtil.parse(str, format);
} }
// 默认转换
final Object obj = getObj(key);
if (null == obj) {
return defaultValue;
}
return Convert.toDate(obj, defaultValue); return Convert.toDate(obj, defaultValue);
} }

View File

@@ -450,6 +450,27 @@ public class JSONObjectTest {
Assert.assertEquals(DateUtil.beginOfDay(date), parse.getDate("date")); Assert.assertEquals(DateUtil.beginOfDay(date), parse.getDate("date"));
} }
@Test
public void setCustomDateFormatTest(){
JSONConfig jsonConfig = JSONConfig.create();
jsonConfig.setDateFormat("#sss");
jsonConfig.setOrder(true);
Date date = DateUtil.parse("2020-06-05 11:16:11");
JSONObject json = new JSONObject(jsonConfig);
json.set("date", date);
json.set("bbb", "222");
json.set("aaa", "123");
String jsonStr = "{\"date\":1591326971,\"bbb\":\"222\",\"aaa\":\"123\"}";
Assert.assertEquals(jsonStr, json.toString());
// 解析测试
final JSONObject parse = JSONUtil.parseObj(jsonStr, jsonConfig);
Assert.assertEquals(date, parse.getDate("date"));
}
@Test @Test
public void getTimestampTest(){ public void getTimestampTest(){
String timeStr = "1970-01-01 00:00:00"; String timeStr = "1970-01-01 00:00:00";

View File

@@ -3,6 +3,7 @@ package cn.hutool.jwt;
import cn.hutool.core.codec.Base64; import cn.hutool.core.codec.Base64;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
@@ -19,11 +20,9 @@ import java.util.Map;
public class Claims implements Serializable { public class Claims implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private JSONObject claimJSON; private final JSONConfig CONFIG = JSONConfig.create().setDateFormat("#sss").setOrder(true);
public Claims() { private JSONObject claimJSON;
this.claimJSON = new JSONObject();
}
/** /**
* 增加Claims属性如果属性值为{@code null},则移除这个属性 * 增加Claims属性如果属性值为{@code null},则移除这个属性
@@ -32,6 +31,7 @@ public class Claims implements Serializable {
* @param value 属性值 * @param value 属性值
*/ */
protected void setClaim(String name, Object value) { protected void setClaim(String name, Object value) {
init();
Assert.notNull(name, "Name must be not null!"); Assert.notNull(name, "Name must be not null!");
if (value == null) { if (value == null) {
claimJSON.remove(name); claimJSON.remove(name);
@@ -59,6 +59,7 @@ public class Claims implements Serializable {
* @return 属性 * @return 属性
*/ */
public Object getClaim(String name) { public Object getClaim(String name) {
init();
return this.claimJSON.getObj(name); return this.claimJSON.getObj(name);
} }
@@ -68,6 +69,7 @@ public class Claims implements Serializable {
* @return JSON字符串 * @return JSON字符串
*/ */
public JSONObject getClaimsJson() { public JSONObject getClaimsJson() {
init();
return this.claimJSON; return this.claimJSON;
} }
@@ -78,11 +80,18 @@ public class Claims implements Serializable {
* @param charset 编码 * @param charset 编码
*/ */
public void parse(String tokenPart, Charset charset) { public void parse(String tokenPart, Charset charset) {
this.claimJSON = JSONUtil.parseObj(Base64.decodeStr(tokenPart, charset)); this.claimJSON = JSONUtil.parseObj(Base64.decodeStr(tokenPart, charset), CONFIG);
} }
@Override @Override
public String toString() { public String toString() {
init();
return this.claimJSON.toString(); return this.claimJSON.toString();
} }
private void init(){
if(null == this.claimJSON){
this.claimJSON = new JSONObject(CONFIG);
}
}
} }

View File

@@ -1,5 +1,6 @@
package cn.hutool.jwt; package cn.hutool.jwt;
import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.KeyUtil; import cn.hutool.crypto.KeyUtil;
import cn.hutool.jwt.signers.AlgorithmUtil; import cn.hutool.jwt.signers.AlgorithmUtil;
import cn.hutool.jwt.signers.JWTSigner; import cn.hutool.jwt.signers.JWTSigner;
@@ -113,6 +114,7 @@ public class JWTSignerTest {
.setPayload("sub", "1234567890") .setPayload("sub", "1234567890")
.setPayload("name", "looly") .setPayload("name", "looly")
.setPayload("admin", true) .setPayload("admin", true)
.setExpiresAt(DateUtil.tomorrow())
.setSigner(signer); .setSigner(signer);
String token = jwt.sign(); String token = jwt.sign();

View File

@@ -1,5 +1,6 @@
package cn.hutool.jwt; package cn.hutool.jwt;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.signers.JWTSignerUtil; import cn.hutool.jwt.signers.JWTSignerUtil;
import org.junit.Assert; import org.junit.Assert;
@@ -14,11 +15,12 @@ public class JWTTest {
.setPayload("sub", "1234567890") .setPayload("sub", "1234567890")
.setPayload("name", "looly") .setPayload("name", "looly")
.setPayload("admin", true) .setPayload("admin", true)
.setPayload(RegisteredPayload.EXPIRES_AT, DateUtil.parse("2022-01-01"))
.setKey(key); .setKey(key);
String rightToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9." + String rightToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9." +
"eyJzdWIiOiIxMjM0NTY3ODkwIiwiYWRtaW4iOnRydWUsIm5hbWUiOiJsb29seSJ9." + "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Imxvb2x5IiwiYWRtaW4iOnRydWUsImV4cCI6IjE2NDA5NjY0MDAifQ." +
"U2aQkC2THYV9L0fTN-yBBI7gmo5xhmvMhATtu8v0zEA"; "c9qo9Z9vdN2gulvOEReU9iEi0bqgyVqjaNKbP1DmTL4";
String token = jwt.sign(); String token = jwt.sign();
Assert.assertEquals(token, rightToken); Assert.assertEquals(token, rightToken);