package xiaozhi.modules.security.config; import java.text.SimpleDateFormat; import java.util.List; import java.util.Locale; import java.util.TimeZone; import jakarta.servlet.http.HttpServletRequest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.ByteArrayHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.ResourceHttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter; import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; import xiaozhi.common.utils.DateUtils; @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowCredentials(true) .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .maxAge(3600); } @Override public void configureMessageConverters(List> converters) { // 特殊用途的转换器 converters.add(new ByteArrayHttpMessageConverter()); converters.add(new ResourceHttpMessageConverter()); // 通用转换器 converters.add(new StringHttpMessageConverter()); converters.add(new AllEncompassingFormHttpMessageConverter()); // JSON 转换器 converters.add(jackson2HttpMessageConverter()); } @Bean public MappingJackson2HttpMessageConverter jackson2HttpMessageConverter() { MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); ObjectMapper mapper = new ObjectMapper(); // 忽略未知属性 mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // 设置时区 mapper.setTimeZone(TimeZone.getTimeZone("GMT+8")); // 配置Java8日期时间序列化 JavaTimeModule javaTimeModule = new JavaTimeModule(); javaTimeModule.addSerializer(java.time.LocalDateTime.class, new LocalDateTimeSerializer( java.time.format.DateTimeFormatter.ofPattern(DateUtils.DATE_TIME_PATTERN))); javaTimeModule.addSerializer(java.time.LocalDate.class, new LocalDateSerializer( java.time.format.DateTimeFormatter.ofPattern(DateUtils.DATE_PATTERN))); javaTimeModule.addSerializer(java.time.LocalTime.class, new LocalTimeSerializer(java.time.format.DateTimeFormatter.ofPattern("HH:mm:ss"))); javaTimeModule.addDeserializer(java.time.LocalDateTime.class, new LocalDateTimeDeserializer( java.time.format.DateTimeFormatter.ofPattern(DateUtils.DATE_TIME_PATTERN))); javaTimeModule.addDeserializer(java.time.LocalDate.class, new LocalDateDeserializer( java.time.format.DateTimeFormatter.ofPattern(DateUtils.DATE_PATTERN))); javaTimeModule.addDeserializer(java.time.LocalTime.class, new LocalTimeDeserializer(java.time.format.DateTimeFormatter.ofPattern("HH:mm:ss"))); mapper.registerModule(javaTimeModule); // 配置java.util.Date的序列化和反序列化 SimpleDateFormat dateFormat = new SimpleDateFormat(DateUtils.DATE_TIME_PATTERN); mapper.setDateFormat(dateFormat); // Long类型转String类型 SimpleModule simpleModule = new SimpleModule(); simpleModule.addSerializer(Long.class, ToStringSerializer.instance); simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance); mapper.registerModule(simpleModule); converter.setObjectMapper(mapper); return converter; } /** * 国际化配置 - 根据请求头中的Accept-Language设置语言环境 */ @Bean public LocaleResolver localeResolver() { return new AcceptHeaderLocaleResolver() { @Override public Locale resolveLocale(HttpServletRequest request) { String acceptLanguage = request.getHeader("Accept-Language"); if (acceptLanguage == null || acceptLanguage.isEmpty()) { return Locale.getDefault(); } // 解析Accept-Language请求头中的首选语言 String[] languages = acceptLanguage.split(","); if (languages.length > 0) { // 提取第一个语言代码,去除可能的质量值(q=...) String[] parts = languages[0].split(";" + "\\s*"); String primaryLanguage = parts[0].trim(); // 根据前端发送的语言代码直接创建Locale对象 if (primaryLanguage.equals("zh-CN")) { return Locale.SIMPLIFIED_CHINESE; } else if (primaryLanguage.equals("zh-TW")) { return Locale.TRADITIONAL_CHINESE; } else if (primaryLanguage.equals("en-US")) { return Locale.US; } else if (primaryLanguage.equals("de-DE")) { return Locale.GERMANY; } else if (primaryLanguage.equals("vi-VN")) { return Locale.forLanguageTag("vi-VN"); } else if (primaryLanguage.startsWith("zh")) { // 对于其他中文变体,默认使用简体中文 return Locale.SIMPLIFIED_CHINESE; } else if (primaryLanguage.startsWith("en")) { // 对于其他英文变体,默认使用美式英语 return Locale.US; } else if (primaryLanguage.startsWith("de")) { // 对于其他德语变体,默认使用德语 return Locale.GERMANY; } else if (primaryLanguage.startsWith("vi")) { // 对于其他越南语变体,默认使用越南语 return Locale.forLanguageTag("vi-VN"); } } // 如果没有匹配的语言,使用默认语言 return Locale.getDefault(); } }; } }