SpringMVC统一配置接口WebMvcConfigurer功能

接口说明 WebMvcConfigurer是Spring提供的统一配置接口,用于自定义Spring MVC的配置,全局更改服务的行为,提供的可配置项: 方法名称 参数 用途 addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) List<HandlerMethodArgumentResolver> argumentResolvers 添加自定义的 HandlerMethodArgumentResolver 用于解析方法参数。 addCorsMappings(CorsRegistry registry) CorsRegistry registry 配置跨域资源共享 (CORS) addFormatters(FormatterRegistry registry) FormatterRegistry registry 添加自定义的格式化程序和转换器 addInterceptors(InterceptorRegistry registry) InterceptorRegistry registry 添加自定义的拦截器 addRequestMappings(RequestMappingInfo customization, Class<Controller> controllerClass) RequestMappingInfo customization, Class<Controller> controllerClass 关联自定义请求映射到具控制器类 addResourceHandlers(ResourceHandlerRegistry registry) ResourceHandlerRegistry registry 配置资源处理,如静态资源路径 addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) List<HandlerMethodReturnValueHandler> returnValueHandlers 添加自定义的 HandlerMethodReturnValueHandler 用于处理方法返回值 addViewControllers(ViewControllerRegistry registry) ViewControllerRegistry registry 注册视图控制器 configureAsyncSupport(AsyncSupportConfigurer configurer) AsyncSupportConfigurer configurer 配置异步支持 configureContentNegotiation(ContentNegotiationConfigurer configurer) ContentNegotiationConfigurer configurer 配置内容协商策略 configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) DefaultServletHandlerConfigurer configurer 启用默认 Servlet 处理 configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) List<HandlerExceptionResolver> exceptionResolvers 配置异常处理程序 configureMessageConverters(List<HttpMessageConverter<?>> converters) List<HttpMessageConverter<?>> converters 配置自定义的 HttpMessageConverter configurePathMatch(PathMatchConfigurer configurer) PathMatchConfigurer configurer 配置路径匹配规则 configureViewResolvers(ViewResolverRegistry registry) ViewResolverRegistry registry 配置视图解析器 extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) List<HandlerExceptionResolver> exceptionResolvers 扩展异常处理程序 extendMessageConverters(List<HttpMessageConverter<?>> converters) List<HttpMessageConverter<?>> converters 扩展自定义的 HttpMessageConverter extendInterceptors(List<HandlerInterceptor> interceptors) List<HandlerInterceptor> interceptors 扩展拦截器 extendArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) List<HandlerMethodArgumentResolver> argumentResolvers 扩展自定义的 HandlerMethodArgumentResolver 用于解析方法参数。 extendReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) List<HandlerMethodReturnValueHandler> returnValueHandlers 扩展自定义的 HandlerMethodReturnValueHandler 用于处理方法返回值。 extendViewResolvers(List<ViewResolver> viewResolvers) List<ViewResolver> viewResolvers 扩展视图解析器 关联类 WebMvcConfigurationSupport EnableWebMvc 接口常用方法 接口提供了将近20个方法对Spring的配置进行调整,本次只针对常用的Rest接口开发相关内容进行展开学习研究 ...

2025-03-28 · 3 min · 461 words · tomyli

基于Spring initializr实现自己的项目模板

介绍 先前通过 Apache Maven Archetype 生成了一个项目脚手架1.0版本,模板比较固定,无法根据需要进行灵活定制,经过调研后,发现可基于Spring Starter项目进行定制,脚手架2.0版本也就应运而生。 目标 快速创建最小可运行工程 基础组件依赖管理 版本管理 帮助信息 按需生成项目结构 最终效果 实现 主流程 获取配置 通过请求服务根路径获取脚手架信息,对应接口代码 如请求: http://localhost:8080 会返回以下内容信息 接口返回了服务支持配置的元数据信息 生成工程代码 用户选择配置相应功能后,点击生成按钮,会调用 http://localhost:8080/start.zip 接口将配置信息传给服务,服务根据信息生成代码 核心功能实现 项目工程由以下几方面组成: application.yml文件 工程目录(controller, servier…) auto_publish相关目录 trpc_java.yaml文件 配置相关 日志配置文件 web服务相关 httpApi接口 httpApi实现类StartController Maven依赖管理 主启动程序自定义 测试辅助开发相关自定义 applicationTest 依赖管理 根据现有常用的 Peacock 框架功能包,依赖管理配置以下模块: Starter Integration Provider Data Testing MQ Job 实践 生成一个最小可运行Web应用 命令行快速生成 curl -L 'http://localhost:8080/start.zip?type=peacock-project&bootVersion=1.5.7.RELEASE&groupId=com.yuewen.bookcoop&artifactId=solution_demo&name=solution_demo101&version=1.0.0-SNAPSHOT&language=java&packageName=com.yuewen.bookcoop.solution_demo&javaVersion=1.8&packaging=jar&description=solution_demo101&dependencies=integration-web&dependencies=peacock-test&dependencies=integration-common&dependencies=starter' -o solution_demo.zip 具体的依赖库元信息可以在根路径下请求获得,具体依赖信息为dependencies值对应id的值 IDEA中生成 Idea配置脚手架地址 使用本地地址如: http://localhost:8080 配置工程信息 填写好相关的业务信息与版本信息 选择依赖模块 Web应用需选择以下模块: Peacock Trpc Starter Integration Web Integration Common Peacock Test 选择完成后点击 生成 按钮生成代码 ...

2024-10-15 · 1 min · 100 words · tomyli

JAVA中如何判断对象与类的关系之-instanceOf, Class.isInstance, Class.isAssignableFrom

前言 在开发中,常常会碰到检查JAVA对象是不是指定类型的情况,在JAVA中提供了以下几种方法实现此类需求: instanceOf Class.isInstance() Class.isAssignbleFrom() 今天对此三种实现进行具体学习,以加深理解并更好的使用 准备工作 先创建一个名为 Shape 的接口,一个实现了 Shape 接口的类 Triangle , 再定义一个继承 Triangle 类的类 IsoscelesTriangle public interface Shape { } public class Triangle implements Shape { } public class IsoscelesTriangle extends Triangle { } 以上三个类的类图关系如下 instanceOf instanceOf 是JAVA中的一个关键字,用于判断 实例对象是否是指定类型的子类型 ,常用于类型转换(cast)之前进行判断,操作的元素是一个对象和一个类型 Shape shape = new Triangle(); Triangle triangle = new Triangle(); IsoscelesTriangle isoscelesTriangle = new IsoscelesTriangle(); Shape nonspecificShape = null; assertTrue(shape instanceof Shape); assertTrue(triangle instanceof Shape); assertTrue(isoscelesTriangle instanceof Shape); assertFalse(nonspecificShape instanceof Shape); assertTrue(shape instanceof Triangle); assertTrue(triangle instanceof Triangle); assertTrue(isoscelesTriangle instanceof Triangle); assertFalse(nonspecificShape instanceof Triangle); assertFalse(shape instanceof IsoscelesTriangle); assertFalse(triangle instanceof IsoscelesTriangle); assertTrue(isoscelesTriangle instanceof IsoscelesTriangle); assertFalse(nonspecificShape instanceof IsoscelesTriangle); 上面例子测试 instanceOf 左侧对象是否是右侧类型的实例类型 ...

2022-12-12 · 2 min · 249 words · tomyli

Java枚举学习

枚举 枚举是指包含指定个数特定类型的实例类,所有枚举类默认都继承 java.lang.Enum ,枚举类是可序列化、可比较的 public enum Person { MAN, WOMAN; } public static void main(String[] args) { System.out.println(Person.MAN); } MAN 枚举构造器 枚举中自动生成的无参构造器默认是private的 显示定义的构造器只能是私有或无访问符的,即枚举不可以从外部进行实例化 无参构造器 public enum Person { MAN(), WOMAN(); Person() {} } public static void main(String[] args) { for(Person person : Person.values()) { System.out.println(person); } } MAN WOMAN 带参构造器 public enum Person { MAN(1), WOMAN(2), UNKNOWN, ; Person() {} Person(int status) { this.status = status; } public int status; } public static void main(String[] args) { for(Person person : Person.values()) { System.out.println(person.status); } } 1 2 0 枚举类初始化 枚举类的初始化与一般类的初始化过程(静态代码块->构造器代码块->构造函数)不同,它的执行顺序为:实例构造器代码块->构造函数->静态常量代码块,以下代码进行演示 ...

2022-11-23 · 3 min · 477 words · tomyli

让好代码生生不息-更好的使用String

开发中常用的String操作 开发中经常用到的操作有: 格式化/日志格式化 字符串判断 字符串处理,常见的如处理字符串的第一个/最后一个字符 String.format String.format()是一个格式化的方法,使用%为前缀来表示要格式化的内容占位,一般的使用方法为: String.format("test result is %s", "success"); 但是当要格式化的占位符与参数个数不同时会发生什么呢? 占位符个数与参数个数相同 如上代码,可以正常进行输出: test result is success 占位符个数少于参数个数 String.format("test result is %s", "success", "other"); 可以正常打印,输出结果为: test result is success 占位符个数多于参数个数 String.format("test result is %s %s %s", "success", "other"); 抛出了异常java.util.MissingFormatArgumentException: Format specifier ‘%s’ 问题总结 为什么占位符数少于参数个数可以正常执行,而多于参数个数却报了异常?看JAVADOC发现,如果占位符个数少于参数个数,则多余的参数被忽略,如果多于参数个数,则在进行解析时会判断待处理占位符位置与参数个数,主要代码逻辑如下: if (args != null && lasto > args.length - 1) throw new MissingFormatArgumentException(fs.toString()); 所以在使用String.format方法 切记 要参数个数多于待解析占位符的个数,这种问题常因为Copy操作后,处理了部分参数而忘记对应处理占位符 替换方案 目前看到很多的老代码打印日志时大都使用String.format(),可以改成slf4j的{} 还可以使用Apache common utils中的StringUtils.joinWith()或者Google guava的Joiner连接器 Apache commons utils-StringUtils 在StringUtils中有一个isNumeric方法,用来判断字符串是不是数字,那下面的代码会返回什么呢? ...

2021-08-23 · 2 min · 221 words · tomyli

让好代码生生不息-更好的对待NULL

什么样的代码是好代码 易读的代码,行云流水的代码 JAVA中的NULL处理 众所周知,在Java代码中总是少不了一堆的判null逻辑,在代码bug中,NullPointerException出镜率也是非常高的,尤其是现在的主流分布式架构,一个web接口要调用后端的N个RPC服务来实现功能,基于防御编程的思想,判null就更重要了 在处理NULL时怎么做更好 IDE 既然无法避免null,IDE就给程序员增加了可以快速判断空的功能,比如在IDEA中,可以使用Postfix功能,在对象上o使用.nn来快速输入if(o != null) {} JAVA基础类库 近期的JDK版本也针对null判断增加了一些实用的方法 Objects类 JAVA8在Objects工具提供了isNull()和nonNull()方法,JAVA9又增加了requireNonNullElse()和requireNonNullElseGet()来给待处理对象增加设置默认值的方法 知名三方库 Apache common utils中提供了非常多的判空工具类,如针对String操作的StringUtils类和针对集合操作的CollectionUtils、MapUtils、ListUtils、SetUtils,这几个类都有一些典型的方法来进行判空处理,通用的方法如下: StringUtils isEmpty()/isNotEmpty() 判断String是否为空/不空 isBlank()/isNoneBlank() 判断String是否为空/不空,这类方法还会判断实际值是否为空串 defaultString() 此方法允许在String为null时为返回空串 defaultIfBlank()/defaultIfEmpty() 此方法允许在String为空串或null时设置一个默认值 集合类Utils isEmpty()/isNotEmpty() 判断集合是否为空/不空 emptyIfNull() 这是一个很有用的方法,当传入对象为空时则返回设置的默认对象,可以很好的根治if处理null的问题,下面两段代码演示一下 正常情况下有if判断 List<Object> values = rpcClient.getFromRpcList(); if(CollectionUtils.isNotEmpty(values)) { return values .forEach(System.out::println); } 使用emptyIfNull方法 return CollectionUtils.emptyIfNull(rpcClient.getFromRpcList()) .forEach(System.out::println); 这样保证了代码编写的连贯性,爽! 此方法在ListUtis、MapUtils、SetUtils中也有提供 defaultIfNull() 此方法允许在集合为null时设置一个默认值,也是可以链式操作 优秀的Coder 在编写通用方法时,对于有null返回的情况可以使用返回默认值来代替null 不返回空,以空对象来代替 比如返回一个new Object() ...

2021-07-17 · 1 min · 60 words · tomyli

2020-ARTS-打卡第十四天

Algorithm 题目 题目描述 98.验证二叉搜索树,给定一个二叉树,判断其是否是一个有效的二叉搜索树。假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的树 节点的右子树只包含大于当前节点的树 所有左子树及右子树自身也必须是二叉搜索树 题目解答 import java.util.Stack; public class ValidBST { public boolean isValidBST (TreeNode root) { Stack<TreeNode> stack = new Stack<>(); double inorder = -Double.MAX_VALUE; while (!stack.isEmpty() || root != null) { while (root != null) { stack.push(root); root = root.left; } root = stack.pop(); if (inorder >= root.val) { return false; } inorder = root.val; root = root.right; } return true; } } 使用中序遍历(即左->根->右)来实现,从左至右进行比对,每次与上次保存的值进行对比,如果当前节点值比上次保存的值小,则可以判定此树不是二叉搜索树。时间复杂度为O(n),空间复杂度为O(n) ...

2020-04-20 · 1 min · 126 words · tomyli

2020-ARTS-打卡第十三天

Algorithm 题目 题目描述 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。答案中不可以包含重复的三元组。 题目解答 import java.util.ArrayList; import java.util.Arrays; import java.util.List; class Solution { public List<List<Integer>> threeSum(int[] nums) { List<List<Integer>> result = new ArrayList<>(); if(null == nums || nums.length < 3) { return result; } Arrays.sort(nums); for (int i = 0; i < nums.length; i ++) { if(nums[i] > 0) { break; } if(i > 0 && nums[i] == nums[i - 1]) { continue; } int L = i + 1; int R = nums.length - 1; while (L < R) { int target = nums[i] + nums[L] + nums[R]; if (target == 0) { result.add(Arrays.asList(nums[i], nums[L], nums[R])); while (L < R && nums[L] == nums[L + 1]) L++; while (L < R && nums[R] == nums[R - 1]) R--; L++; R--; } else if (target < 0) { L++; } else { R--; } } } return result; } 一共有三种解法,一是三层for循环,时间复杂度为O(n3);二是二层for循环外加Hash表,时间复杂度为O(n2),增加了空间复杂度O(n);第三种就是上面的解法,排序后从两侧开始匹配,时间复杂度为O(n2),空间复杂度为O(1) ...

2020-04-08 · 2 min · 229 words · tomyli

2020-ARTS-打卡第十二天

Algorithm 题目 题目描述 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。242 valid anagram 题目解答 可以使用先排序后判断的方法来实现,这样的时间复杂度为O(nlog(n))。更好的方法是借助Hash表来实现,可以达到O(n)的时间复杂度。 public class ValidAnagram { public boolean isAnagram(String s, String t) { if (null == s || null == t || s.length() != t.length()) { return false; } Map<Character, Integer> map = new HashMap<>(); final char[] chars = s.toCharArray(); for (int i = 0; i < chars.length; i++) { final char key = s.charAt(i); map.put(key, map.getOrDefault(key, 0) + 1); final char key1 = t.charAt(i); map.put(key1, map.getOrDefault(key1, 0) - 1); } for (Map.Entry<Character, Integer> entry : map.entrySet()) { if (0 != entry.getValue()) { return false; } } return true; } } Review 你可能不知道的SHELLCoolShell左耳朵耗子2012年的关于强大Shell的文章,里面列出了很多有用的命令,看完后收获颇丰。针对实际使用场景,列出我认为暂时可以直接使用的一些操作命令。 ...

2020-03-30 · 1 min · 150 words · tomyli

2020-ARTS-打卡第十一天

Algorithm 题目 题目描述 给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回滑动窗口中的最大值。 239 sliding-window-maximum 题目解答 一般与滑动窗口有关的问题都可以使用双端队列来处理。 import java.util.ArrayDeque; import java.util.List; import java.util.ArrayList; public class MaxSlidingWindow { private ArrayDeque<Integer> window = new ArrayDeque<>(); public int[] slidingWindowMax(int[] nums, int k) { if(nums.length == 0) { return new int[0]; } List<Integer> res = new ArrayList<>(); for(int i = 0; i < nums.length; i++) { if(i >= k && window.getFirst() <= i - k) { window.pollFirst(); } while(!window.isEmpty() && nums[window.getLast()] < nums[i]) { window.pollLast(); } window.add(i); if(i >= k - 1) { res.add(nums[window.getFirst()]); } } return res.stream().mapToInt(i->i).toArray(); } } Review Consistent_hashing一致性Hash算法。 ...

2020-03-23 · 1 min · 135 words · tomyli