首页 文章 精选 留言 我的

精选列表

搜索[SpringBoot],共4548篇文章
优秀的个人博客,低调大师

SpringBoot 优雅停服

一、介绍 当外部流量请求到服务端接口执行业务逻辑的时候,若服务端此时执行关机 (kill),spring boot 默认情况会直接关闭容器(tomcat 等),导致此业务逻辑执行失败。在一些业务场景下:会出现数据不一致的情况,事务逻辑不会回滚。 在最新的 spring boot 2.3 版本,内置此功能,不需要再自行扩展容器线程池来处理, 目前 spring boot 嵌入式支持的 web 服务器(Jetty、Reactor Netty、Tomcat 和 Undertow)以及反应式和基于 Servlet 的 web 应用程序都支持优雅停机功能。 此处支持的 shutdown 行为,我们看下源码枚举如下: public enum Shutdown { /** * 优雅停机 (限期停机) * */ GRACEFUL, /** * 立即停机 */ IMMEDIATE; } 二、使用 当使用server.shutdown=graceful启用时,在 web 容器关闭时,web 服务器将不再接收新请求,并将等待活动请求完成的缓冲期。 缓冲期 timeout-per-shutdown-phase 配置:默认时间为 30S, 意味着最大等待 30S,超时候无论线程任务是否执行完毕都会停机处理,一定要根据项目实际需要合理设置。 以上配置完毕,重新发布以后,服务端就支持优雅停服。 三、触发优雅停服 1、对进城PID执行kill -2 而不是 kill -9 kill -9,暴力美学强制杀死进程,不会执行 ShutdownHook;但是 kill -2 相当于快捷键 Ctrl + C 会触发 Java 的 ShutdownHook 事件处理进行优雅停机或者一些后置处理。可参考以下源码: @Override public void registerShutdownHook() { if (this.shutdownHook == null) { // No shutdown hook registered yet. this.shutdownHook = new Thread(SHUTDOWN_HOOK_THREAD_NAME) { @Override public void run() { synchronized (startupShutdownMonitor) { doClose(); } } }; Runtime.getRuntime().addShutdownHook(this.shutdownHook); } } 2、通过 actuate 端点实现优雅停机 POST 请求 /actuator/shutdown 即可执行优雅关机。源码解析如下: @Endpoint(id = "shutdown", enableByDefault = false) public class ShutdownEndpoint implements ApplicationContextAware { @WriteOperation public Map<String, String> shutdown() { Thread thread = new Thread(this::performShutdown); thread.setContextClassLoader(getClass().getClassLoader()); thread.start(); } private void performShutdown() { try { Thread.sleep(500L); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } // 此处close 逻辑和上边 shutdownhook 的处理一样 this.context.close(); } } 三、不同spring boot嵌入式 web 容器优雅停机行为区别 -------------------------------------- 版权声明:本文为【PythonJsGo】博主的原创文章,转载请附上原文出处链接及本声明。 博主主页:https://my.oschina.net/u/3375733 本篇文章同步在个人公众号:

优秀的个人博客,低调大师

SpringBoot导入导出Excel

简单、快速的导入导出Excel 一、安装依赖 推荐使用最新版本,可通过文章末尾官方文档链接跳转查看 <dependency> <groupId>cn.gjing</groupId> <artifactId>tools-excel</artifactId> <version>2.2.9</version> </dependency> 二、Excel导出 1、单表头 定义Excel映射实体, @Data是lombok的注解 /** * @author Gjing **/ @Data @Excel("单级表头") public class SingleHead { @ExcelField("姓名") private String userName; @ExcelField(value = "年龄", format = "0") private Integer userAge; @ExcelField("性别") private Gender gender; @ExcelField("爱好") private String favorite; } /** * @author Gjing **/ @RestController public class UserController { @GetMapping("/test_export") @ApiOperation("导出一级表头") public void testExport(HttpServletResponse response) { //指定映射的实体为刚刚定义的 ExcelFactory.createWriter(SingleHead.class, response) .write(null) .flush(); } } 2、多级表头 数组中的每个值代表着一级表头 /** * @author Gjing **/ @Data @Excel("多级表头") public class MultiHead { @ExcelField({"用户名","用户名"}) private String userName; @ExcelField({"年龄","年龄"}) private Integer age; @ExcelField({"形态","身高"}) private BigDecimal height; @ExcelField({"形态","体重"}) private BigDecimal weight; } /** * @author Gjing **/ @RestController public class TestController { @GetMapping("/test_export") @ApiOperation("多级表头") public void testExport(HttpServletResponse response) { ExcelFactory.createWriter(MultiHead.class, response) //需要在write前激活多级表头,否则不会自动合并 .multiHead(true) .write(null) .flush(); } } 3、带大标题 大标题的起始行是你要插入的sheet中最后一条数据的下一行,如果sheet中没有数据,就是第一行。你可以配置大标题占用的行数和起始单元格下标(默认第一个单元格)和结束单元格下标(默认跟随表头的数量) /** * @author Gjing **/ @RestController public class TestController { @GetMapping("/test") @ApiOperation("含大标题") public void testExport(HttpServletResponse response) { ExcelFactory.createWriter(SingleHead.class, response) //大标题占用两行 .writeTitle(new BigTitle("我是大标题")) .write(null) .flush(); } } 4、下拉框 单元格增加下拉框 注解方式 /** * @author Gjing **/ @Data @Excel("下拉框导出") public class SingleHead { @ExcelField("性别") @ExcelDropdownBox(combobox = {"男", "女"}) private Gender gender; @ExcelField("爱好") private String favorite; } /** * @author Gjing **/ @RestController public class TestController { @GetMapping("/test_export") @ApiOperation("带下拉框") public void testExport(HttpServletResponse response) { ExcelFactory.createWriter(SingleHead.class, response) //需要在write前激活校验 .valid(true) .write(null) .flush(); } } 通过方法设置普通下拉框的选项 /** * @author Gjing **/ @RestController public class TestController { @GetMapping("/test_export") @ApiOperation("带下拉框") public void testExport(HttpServletResponse response) { Map<String, String[]> genderMap = new HashMap<>(8); //key为实体类的字段名,使用方法进行设置时,实体字段的@ExcelDropdownBox注解不在需要指定combobox //如果指定了也会去覆盖注解中的值 genderMap.put("gender", new String[]{"男", "女"}); ExcelFactory.createWriter(SingleHead.class, response) .valid(true) .write(null, genderMap) .flush(); } } 5、时间校验 导出时给列表头下方的单元格增加时间校验 /** * @author Gjing **/ @Data @Excel public class SingleHead { @ExcelField("姓名") private String userName; @ExcelField(value = "年龄", format = "0") private Integer userAge; @ExcelField(value = "生日", format = "yyyy-MM-dd") @ExcelDateValid(expr1 = "2000-01-01", operatorType = LESS_OR_EQUAL, errorContent = "出生日期不能超过2000年") private Date birthday; } /** * @author Gjing **/ @RestController public class TestController { @GetMapping("/test_export") @ApiOperation("带时间校验") public void testExport(HttpServletResponse response) { ExcelFactory.createWriter(SingleHead.class, response) //需要在write前激活校验 .valid(true) .write(null) .flush(); } } 6、数字、文本校验 导出时给列表头下方的单元格增加数值校验。可以对数字的大小,文本的长度进行校验 /** * @author Gjing **/ @Data @Excel public class SingleHead { @ExcelField("姓名") //对输入的名称字数进行校验,字数限制小于4 @ExcelNumericValid(validType = TEXT_LENGTH,operatorType = LESS_THAN,expr1 = "4",errorContent = "姓名字数小于4") private String userName; } /** * @author Gjing **/ @RestController public class TestController { @GetMapping("/test_export") @ApiOperation("带数值校验") public void testExport(HttpServletResponse response) { ExcelFactory.createWriter(SingleHead .class, response) //需要在write前激活校验 .valid(true) .write(null) .flush(); } } 7、数据转换 导出时对数据进行加工或者添加默认值,支持注解方式和接口方式 注解方式 /** * @author Gjing **/ @Data @Excel public class SingleHead { @ExcelField("姓名") private String userName; @ExcelField(value = "年龄", format = "0") //对每个人的年龄乘以10 @ExcelDataConvert(expr1 = "#userAge * 10") private Integer userAge; } 接口方式 /** * @author Gjing **/ public class MyDataConvert implements DataConvert<SingleHead> { @Override public Object toEntityAttribute(Object o, Field field) { return null; } @Override public Object toExcelAttribute(SingleHead singleHead, Object value, Field field) { return (int) value * 10; } } 实现接口后需要在你需要转换的字段上指定转换器 /** * @author Gjing **/ @Data @Excel public class SingleHead { @ExcelField("姓名") private String userName; @ExcelField(value = "年龄", format = "0", convert = MyDataConvert.class) private Integer userAge; } 导出方法调用最后一定要使用flush()方法进行数据刷新到Excel文件中 三、导入 导入的实体类皆采用导出的实体类 1、单表头 /** * @author Gjing **/ @RestController public class TestController { @Resource private UserService userService; @PostMapping("/user_import") @ApiOperation("导入单表头") public void userImport(MultipartFile file) throws IOException { ExcelFactory.createReader(file, SingleHead.class) //在read()方法前通过订阅方法增加一个结果监听器,该监听器会在每一次read()结束之后触发 .subscribe(e -> this.userService.saveUsers(e)) .read() .finish(); } } 2、多级表头 前文有提到多级表头时,最后一级为实际表头,所以要在导入时指定实际表头开始下标,由于导出的模板映射实体设置两级表头,因此这里的实际表头为下标为1(Excel行和列下标都是默认0开始的) /** * @author Gjing **/ @RestController public class TestController { @Resource private UserService userService; @PostMapping("/user_import") @ApiOperation("导入单表头") public void userImport(MultipartFile file) throws IOException { ExcelFactory.createReader(file, SingleHead.class) //在read()方法前通过订阅方法增加一个结果监听器,该监听器会在每一次read()结束之后触发 //如果Excel中数据量太大,不建议使用结果监听器,会造成生成了过多的映射实体对象造成内存溢出 .subscribe(e -> this.userService.saveUsers(e)) .read(1) .finish(); } } 在导入调用结束后,一定要在最后调用finish()方法对流进行关闭 四、注解驱动方式的导入导出 如果要使用注解驱动方式,需要在启动类或者配置类标注@EnableExcelDrivenMode注解 1、导出 导出的方法需增加@ExcelWrite注解 a、导出模板 /** * @author Gjing **/ @RestController public class ExcelDriveController { @GetMapping("/export") @ApiOperation("下载Excel模板") @ExcelWrite(mapping = SingleHead.class) public void export() { } } b、导出带标题的模板 导出带大标题的模板,你可以直接设置方法的返回值为bigTitle,也可以使用ExcelWriteWrapper包装器进行数据构造 直接返回方式 @RestController public class ExcelDriveController { @GetMapping("/export") @ApiOperation("导出带大标题的excel") @ExcelWrite(mapping = SingleHead.class) public BigTitle export() { return new BigTitle("啦啦啦"); } } 包装器方式 @RestController public class ExcelDriveController { @GetMapping("/export") @ApiOperation("导出带大标题的excel") @ExcelWrite(mapping = SingleHead.class) public ExcelWriteWrapper excelDrive() { return ExcelWriteWrapper.build() .title(new BigTitle("啦啦啦")); } } c、导出数据 导出带数据的Excel,你可以直接设置方法的返回值为数据List,也可以使用ExcelWriteWrapper包装器进行数据构造,包装器可以用于设置一些属性,如监听器、大标题、导出的数据等等。。 直接返回方式 /** * @author Gjing **/ @RestController public class ExcelDriveController { @Resource private UserService userService; @GetMapping("/export") @ApiOperation("导出带数据的excel") @ExcelWrite(mapping = SingleHead.class) public List<SingleHead> excelDrive() { return this.userService.userList(); } } 包装器方式 @RestController public class ExcelDriveController { @Resource private UserService userService; @GetMapping("/excel_drive") @ApiOperation("导出带数据的excel") @ExcelWrite(mapping = SingleHead.class) public ExcelWriteWrapper export() { return ExcelWriteWrapper.build(userService.userList()); } } 2、导入 导出的方法需要增加@ExcelRead注解 a、导入普通的模板 导入时,需要将方法返回值设置为ExcelReadWrapper,这是导入时的数据包装器,用于设置一些属性,如文件流、监听器、结果订阅... @RestController public class ExcelDriveController { @Resource private UserService userService; @PostMapping("/excel_drive5") @ApiOperation("导入excel") @ExcelRead public ExcelReadWrapper<SingleHead> read1(MultipartFile file) throws IOException { return ExcelReadWrapper.build(SingleHead.class) .data(file) .subscribe(e -> this.userService.saveUsers(e)); } } b、导入带大标题的模板 由上文可得知,如果模板带有大标题,需要我们指定表头开始下标,下标要根据你的模板标题有多少行而定,我们在导出时设置了两行,所以这里配置两行 @RestController public class ExcelDriveController { @Resource private UserService userService; @PostMapping("/excel_drive5") @ApiOperation("导入excel") @ExcelRead(headerIndex = 2) public ExcelReadWrapper<SingleHead> read1(MultipartFile file) throws IOException { return ExcelReadWrapper.build(SingleHead.class) .data(file) .subscribe(e -> this.userService.saveUsers(e)); } } Demo地址:excel-demo 注解参数说明与更多用法可查看:官方文档

优秀的个人博客,低调大师

SpringBoot ~ 拦截器

拦截器 创建拦截器 /** * @author wsyjlly * @create 2019.06.13 - 16:52 **/ public class FileUploadInterceptor implements HandlerInterceptor { private Logger logger = LoggerFactory.getLogger(getClass()); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { logger.debug("FileUploadInterceptor...preHandle"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { logger.debug("FileUploadInterceptor...postHandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { logger.debug("FileUploadInterceptor...afterCompletion"); } } 注册拦截器 注册方式一:一般注册方式 /** * @author wsyjlly * @create 2019.06.12 - 16:17 **/ @Configuration public class WebMvcConfig implements WebMvcConfigurer { /* * 配置拦截器 * */ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new FileUploadInterceptor()). addPathPatterns("/upload").order(1); } } 注册方式二:当拦截器中需要注入变量时须提前加载该拦截器 /** * @author wsyjlly * @create 2019.06.12 - 16:17 **/ @Configuration public class WebMvcConfig implements WebMvcConfigurer { /* * 配置拦截器 * */ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(getFileUploadInterceptor()). addPathPatterns("/upload").order(1); } @Bean public FileUploadInterceptor getFileUploadInterceptor(){ return new FileUploadInterceptor(); } }

资源下载

更多资源
Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册