diff --git a/src/main/java/cn/zhangdeman/config/BaseWebConfig.java b/src/main/java/cn/zhangdeman/config/BaseWebConfig.java new file mode 100644 index 0000000..63b21aa --- /dev/null +++ b/src/main/java/cn/zhangdeman/config/BaseWebConfig.java @@ -0,0 +1,27 @@ +package cn.zhangdeman.config; + + +import jakarta.annotation.Resource; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.List; + +@Configuration +public class BaseWebConfig implements WebMvcConfigurer { + @Resource + private Http404Interceptor http404Interceptor; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(http404Interceptor) + .addPathPatterns("/**")//拦截所有请求 + .excludePathPatterns("/system/**");// 放行登录请求 + } + @Override + public void addArgumentResolvers(List resolvers) { + resolvers.add(new SnakeToCamelCaseArgumentResolver()); + } +} diff --git a/src/main/java/cn/zhangdeman/config/Http404Interceptor.java b/src/main/java/cn/zhangdeman/config/Http404Interceptor.java new file mode 100644 index 0000000..cec1114 --- /dev/null +++ b/src/main/java/cn/zhangdeman/config/Http404Interceptor.java @@ -0,0 +1,29 @@ +package cn.zhangdeman.config; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +// Http404Interceptor 404请求的拦截器 +@Slf4j +@Component +public class Http404Interceptor implements HandlerInterceptor { + @Override + public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse response, Object handler) throws Exception { + // throw new Exception("这里是我自定义的404拦截器"); + return HandlerInterceptor.super.preHandle(httpServletRequest, response, handler); + } + + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { + HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + HandlerInterceptor.super.afterCompletion(request, response, handler, ex); + } +} diff --git a/src/main/java/cn/zhangdeman/config/SnakeToCamelCaseArgumentResolver.java b/src/main/java/cn/zhangdeman/config/SnakeToCamelCaseArgumentResolver.java new file mode 100644 index 0000000..a170f40 --- /dev/null +++ b/src/main/java/cn/zhangdeman/config/SnakeToCamelCaseArgumentResolver.java @@ -0,0 +1,131 @@ +package cn.zhangdeman.config; + +import org.springframework.beans.MutablePropertyValues; +import org.springframework.core.MethodParameter; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +import java.util.HashMap; +import java.util.Map; + +/** + * 下划线参数名转小驼峰属性名的参数解析器 + */ +public class SnakeToCamelCaseArgumentResolver implements HandlerMethodArgumentResolver { + + @Override + public boolean supportsParameter(MethodParameter parameter) { + // 支持带有@ModelAttribute注解的参数 + return parameter.hasParameterAnnotation(ModelAttribute.class); + } + + @Override + public Object resolveArgument(MethodParameter parameter, + ModelAndViewContainer mavContainer, + NativeWebRequest webRequest, + WebDataBinderFactory binderFactory) throws Exception { + + // 1. 创建目标对象实例 + Object target = parameter.getParameterType().getDeclaredConstructor().newInstance(); + + // 2. 创建数据绑定器 + WebDataBinder binder = binderFactory.createBinder(webRequest, target, parameter.getParameterName()); + + // 3. 转换参数名并收集 + Map convertedParams = convertParameterMap(webRequest.getParameterMap()); + + // 4. 绑定转换后的参数 + binder.bind(new MutablePropertyValues(convertedParams)); + + // 5. 返回绑定后的对象 + return binder.getTarget(); + } + + /** + * 将下划线风格的参数Map转换为小驼峰风格的Map + */ + private Map convertParameterMap(Map parameterMap) { + Map result = new HashMap<>(); + + parameterMap.forEach((key, values) -> { + // 转换参数名:user_name -> userName + String camelKey = convertSnakeToCamel(key); + + // 处理数组参数:如果是单值则取第一个元素 + Object value = values.length == 1 ? values[0] : values; + + // 处理嵌套参数:address.home_address -> address.homeAddress + if (camelKey.contains(".")) { + handleNestedParameter(result, camelKey, value); + } else { + result.put(camelKey, value); + } + }); + + return result; + } + + /** + * 处理嵌套参数 + */ + private void handleNestedParameter(Map result, String key, Object value) { + String[] parts = key.split("\\."); + Map currentMap = result; + + for (int i = 0; i < parts.length - 1; i++) { + String part = parts[i]; + + // 如果中间节点不存在,则创建新的Map + if (!currentMap.containsKey(part)) { + currentMap.put(part, new HashMap()); + } + + // 向下钻取 + Object nextLevel = currentMap.get(part); + if (nextLevel instanceof Map) { + currentMap = (Map) nextLevel; + } else { + // 如果中间节点不是Map,则覆盖(这种情况不应该发生) + Map newMap = new HashMap<>(); + currentMap.put(part, newMap); + currentMap = newMap; + } + } + + // 设置最终的值 + currentMap.put(parts[parts.length - 1], value); + } + + /** + * 下划线命名转小驼峰命名 + */ + private String convertSnakeToCamel(String snakeCase) { + if (snakeCase == null || snakeCase.isEmpty()) { + return snakeCase; + } + + StringBuilder result = new StringBuilder(); + boolean nextUpper = false; + + for (int i = 0; i < snakeCase.length(); i++) { + char currentChar = snakeCase.charAt(i); + + if (currentChar == '_') { + nextUpper = true; + } else { + if (nextUpper) { + result.append(Character.toUpperCase(currentChar)); + nextUpper = false; + } else { + result.append(Character.toLowerCase(currentChar)); + } + } + } + + return result.toString(); + } +} \ No newline at end of file