首页 文章 精选 留言 我的

精选列表

搜索[教育数字化],共10000篇文章
优秀的个人博客,低调大师

MeEdu v3.7.1 版本上线,在线教育点播系统

新增 新增微信公众号授权开关控制 PC手机号强制绑定新增退出按钮 修复 修复课程列表分类筛选页码未重置为1 修复PC微信支付收银台页面标题为meedu 修复PC手动支付收银台页面标题为meedu 修复微信公众号授权登录下用户已锁定重复重定向bug Github:https://github.com/Qsnh/meedu Gitee:https://gitee.com/myteng/MeEdu 官网:https://meedu.vip 当前功能概览 视频在线点播 课程评论/视频评论 支持阿里云视频点播、腾讯云视频点播服务 手机号注册/登录(短信登录)/密码找回/手机号绑定 QQ登录/Github登录/微信开放平台扫码登录 课程单独购买/视频单独购买/全站会员三种收费模式 站内消息 支付宝/微信/手动转账三种支付方式 积分功能 视频试看、视频禁止快进 视频播放跑马灯(防录屏) 视频播放统计/课程观看进度/用户观看统计 学习历史/观看记录/课程收藏 优惠码功能 邀请/一级返现/支付宝提现 阿里云短信/云片短信 系统缓存 图片本地存储/七牛云存储/阿里云oss存储 用户协议/用户隐私协议 后台多角色多权限管理 推广链接(用于第三方推广) 70%+的单元测试覆盖率 SEO优化 友情链接 插件系统 模板系统 微信小程序 MeEdu采用 MIT 开源许可证,可以在商业项目中免费使用MeEdu或者基于MeEdu二次开发而不必支付费用。

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

MeEdu v3.7 版本上线,在线教育点播系统

新增 PC点击章节名展开视频 PC导航栏新窗口打开字段 微信公众号授权登录 优化 邀请码/优惠码文案 导航栏样式 PC用户头像样式 PC我的资料页面样式 社交登录流程(含手机号的强制绑定) 图形验证码参数调整 注册IP解析依赖更换为高德API 微信公众号文本消息回复的规则校验 docker的nginx默认上传文件大小配置 修复 登录页面弹出登录框导致图形验证码错误无法登录/注册 课程订阅数量统计 H5的app.js图片上传的报错 移除 删除User模型 移除视频的简单介绍和详细介绍 Github:https://github.com/Qsnh/meedu Gitee:https://gitee.com/myteng/MeEdu 官网:https://meedu.vip 当前功能概览 视频在线点播 课程评论/视频评论 支持阿里云视频点播、腾讯云视频点播服务 手机号注册/登录(短信登录)/密码找回/手机号绑定 QQ登录/Github登录/微信开放平台扫码登录 课程单独购买/视频单独购买/全站会员三种收费模式 站内消息 支付宝/微信/手动转账三种支付方式 积分功能 视频试看、视频禁止快进 视频播放跑马灯(防录屏) 视频播放统计/课程观看进度/用户观看统计 学习历史/观看记录/课程收藏 优惠码功能 邀请/一级返现/支付宝提现 阿里云短信/云片短信 系统缓存 图片本地存储/七牛云存储/阿里云oss存储 用户协议/用户隐私协议 后台多角色多权限管理 推广链接(用于第三方推广) 70%+的单元测试覆盖率 SEO优化 友情链接 插件系统 模板系统 微信小程序 MeEdu采用 MIT 开源许可证,你可以在商业项目中免费使用MeEdu或者基于MeEdu二次 开发而不必支付费用。

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

MeEdu v3.4 版本上线,在线教育点播系统

新增 新增:微信公众号消息回复 新增:微信公众号自定义菜单 新增:订单商品增加商品名,价格,封面字段 新增:后台订单详情 新增:后台课程订阅管理 新增:后台视频订阅管理 新增:后台视频观看记录 新增:用户标签 新增:用户备注 新增:埋点 新增:注册送会员 优化 优化:后台课程和视频评论的API接口(增加部分过滤参数) 优化:后台订单列表API接口(新增部分过滤参数) 优化:依赖更新 优化:后台一大波体验优化 修复 修复:后台用户的VIP删除 Github:https://github.com/Qsnh/meedu Gitee:https://gitee.com/myteng/MeEdu 官网:https://meedu.vip 当前功能概览 视频在线点播 课程评论/视频评论 支持阿里云视频点播、腾讯云视频点播服务 手机号注册/登录(短信登录)/密码找回/手机号绑定 QQ登录/Github登录/微信开放平台扫码登录 课程单独购买/视频单独购买/全站会员三种收费模式 站内消息 支付宝/微信/手动转账三种支付方式 积分功能 视频试看、视频禁止快进 视频播放跑马灯(防录屏) 视频播放统计/课程观看进度/用户观看统计 学习历史/观看记录/课程收藏 优惠码功能 邀请/一级返现/支付宝提现 阿里云短信/云片短信 系统缓存 图片本地存储/七牛云存储/阿里云oss存储 用户协议/用户隐私协议 后台多角色多权限管理 推广链接(用于第三方推广) 70%+的单元测试覆盖率 SEO优化 友情链接 插件系统 模板系统 微信小程序 MeEdu采用 MIT 开源许可证,你可以在商业项目中免费使用MeEdu或者基于MeEdu二次 开发而不必支付费用。

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

MeEdu v3.3 版本上线,在线教育点播系统

本次更新内容如下: 新增 added: 用户登录记录存储 added: 单点登录(不限制,单平台限制,全平台限制。平台有: PC,H5,ANDROID,IOS,MINI) added: 首页导航active routes added: 全局自定义css(PC和H5分开定义) added: 后台远程图片一键同步到本地 added: 幻灯片增加平台字段(pc,h5,mini,android,ios),不同平台读取所在平台的幻灯片 added: 微信小程序一键登录api(手机号一键登录) added: 课程列表增加免费课程过滤 优化 Laravel从5.8升级到6.x 单元测试phpunit升级到8.x 更换zip解压缩依赖(原先的zip扩展包已停止维护) 课程列表显示价格和课程订阅人数 优化注册流程字段,去掉了昵称和再次输入密码,使得注册更加方便 优化登录后的跳转 更新cors跨域扩展包 安装文档更新 优化后台敏感配置为空的情况下不显示*符号 修复 fixed: 微信小程序支付 fixed: 视频详情api接口的课程订阅数量统计 Github:https://github.com/Qsnh/meedu Gitee:https://gitee.com/myteng/MeEdu 官网:https://meedu.vip 当前功能概览 视频在线点播 课程评论/视频评论 支持阿里云视频点播、腾讯云视频点播服务 手机号注册/登录(短信登录)/密码找回/手机号绑定 QQ登录/Github登录/微信开放平台扫码登录 课程单独购买/视频单独购买/全站会员三种收费模式 站内消息 支付宝/微信/手动转账三种支付方式 积分功能 视频试看、视频禁止快进 视频播放跑马灯(防录屏) 视频播放统计/课程观看进度/用户观看统计 学习历史/观看记录/课程收藏 优惠码功能 邀请/一级返现/支付宝提现 阿里云短信/云片短信 系统缓存 图片本地存储/七牛云存储/阿里云oss存储 用户协议/用户隐私协议 后台多角色多权限管理 推广链接(用于第三方推广) 70%+的单元测试覆盖率 SEO优化 友情链接 插件系统 模板系统 微信小程序 MeEdu采用 MIT 开源许可证,你可以在商业项目中免费使用MeEdu或者基于MeEdu二次 开发而不必支付费用。

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

MeEdu v3.2 版本上线,在线教育点播系统

新增 added: 课程章节收缩 added: 用户协议,用户隐私协议,关于我们页面增加自定义Js代码 added: 课程和视频评论控制 added: 视频批量删除 added: 后台积分操作 added: 视频pc和h5的播放器指定 added: 视频试看 added: 视频快进控制 added: 试看标签 优化 优化:系统配置数据改为数据库存储 优化:阿里云相关依赖代码优化 修复 fixed: 搜索页面标题 fixed: helper.php的加载 fixed: 课程观看进度判断 fixed: 傻瓜安装 Github:https://github.com/Qsnh/meedu Gitee:https://gitee.com/myteng/MeEdu 官网:https://meedu.vip 当前功能概览 视频在线点播 课程评论/视频评论 支持阿里云视频点播、腾讯云视频点播服务 手机号注册/登录(短信登录)/密码找回/手机号绑定 QQ登录/Github登录/微信开放平台扫码登录 课程单独购买/视频单独购买/全站会员三种收费模式 站内消息 支付宝/微信/手动转账三种支付方式 积分功能 视频试看、视频禁止快进 视频播放跑马灯(防录屏) 视频播放统计/课程观看进度/用户观看统计 学习历史/观看记录/课程收藏 优惠码功能 邀请/一级返现/支付宝提现 阿里云短信/云片短信 系统缓存 图片本地存储/七牛云存储/阿里云oss存储 用户协议/用户隐私协议 后台多角色多权限管理 推广链接(用于第三方推广) 70%+的单元测试覆盖率 SEO优化 友情链接 插件系统 模板系统 微信小程序 MeEdu采用 MIT 开源许可证,你可以在商业项目中免费使用MeEdu或者基于MeEdu二次 开发而不必支付费用。

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

【熵增教育】探索SpringBoot中的SpringMVC——熵增学院

spring boot就是一个大框架里面包含了许许多多的东西,其中spring就是最核心的内容之一,当然就包含spring mvc。spring mvc 是只是spring 处理web层请求的一个模块。因此他们的关系大概就是这样:spring mvc < spring <springboot。 理清SpringBoot与SpringMVC的关系 Spring 框架就像一个家族,有众多衍生产品例如 boot、security、jpa等等。但他们的基础都是Spring 的 ioc和 aop ioc 提供了依赖注入的容器 aop ,解决了面向横切面的编程,然后在此两者的基础上实现了其他延伸产品的高级功能。 Spring MVC是基于 Servlet 的一个 MVC 框架 主要解决 WEB 开发的问题,因为 Spring 的配置非常复杂,各种XML、 JavaConfig、hin处理起来比较繁琐。 于是为了简化开发者的使用,从而创造性地推出了Spring boot,约定优于配置,简化了spring的配置流程。 说得更简便一些:Spring 最初利用“工厂模式”(DI)和“代理模式”(AOP)解耦应用组件。 大家觉得挺好用,于是按照这种模式搞了一个 MVC框架(一些用Spring 解耦的组件),用开发 web 应用( SpringMVC )。 然后有发现每次开发都写很多样板代码,为了简化工作流程,于是开发出了一些“懒人整合包”(starter),这套就是 Spring Boot。 Spring MVC的功能Spring MVC提供了一种轻度耦合的方式来开发web应用。Spring MVC是Spring的一个模块,式一个web框架。 通过Dispatcher Servlet, ModelAndView 和 View Resolver,开发web应用变得很容易。解决的问题领域是网站应用程序或者服务开发——URL路由、Session、模板引擎、静态Web资源等等。 Spring Boot的功能Spring Boot实现了自动配置,降低了项目搭建的复杂度。 众所周知Spring框架需要进行大量的配置,Spring Boot引入自动配置的概念,让项目设置变得很容易。 Spring Boot本身并不提供Spring框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于Spring框架的应用程序。也就是说,它并不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具。 同时它集成了大量常用的第三方库配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot应用中这些第三方库几乎可以零配置的开箱即用(out-of-the-box),大部分的Spring Boot应用都只需要非常少量的配置代码,开发者能够更加专注于业务逻辑。Spring Boot只是承载者,辅助你简化项目搭建过程的。如果承载的是WEB项目,使用Spring MVC作为MVC框架,那么工作流程和你上面描述的是完全一样的,因为这部分工作是Spring MVC做的而不是Spring Boot。对使用者来说,换用Spring Boot以后,项目初始化方法变了,配置文件变了,另外就是不需要单独安装Tomcat这类容器服务器了,maven打出jar包直接跑起来就是个网站,但你最核心的业务逻辑实现与业务流程实现没有任何变化。 所以,用最简练的语言概括就是: Spring 是一个“引擎”; Spring MVC 是基于Spring的一个 MVC 框架 ; Spring Boot 是基于Spring4的条件注册的一套快速开发整合包。 Spring MVC自动配置 Spring Boot为Spring MVC提供的auto-configuration适用于大多数应用,并在Spring默认功能上添加了以下特性: 引入ContentNegotiatingViewResolver和BeanNameViewResolverbeans。 对静态资源的支持,包括对WebJars的支持。 自动注册Converter,GenericConverter,Formatterbeans。 对HttpMessageConverters的支持。 自动注册MessageCodeResolver。 对静态index.html的支持。 对自定义Favicon的支持。 自动使用ConfigurableWebBindingInitializerbean。 如果保留Spring Boot MVC特性,你只需添加其他的MVC配置(拦截器,格式化处理器,视图控制器等)。你可以添加自己的WebMvcConfigurerAdapter类型的@Configuration类,而不需要注解@EnableWebMvc。如果希望使用自定义的RequestMappingHandlerMapping,RequestMappingHandlerAdapter,或ExceptionHandlerExceptionResolver,你可以声明一个WebMvcRegistrationsAdapter实例提供这些组件。 如果想全面控制Spring MVC,你可以添加自己的@Configuration,并使用@EnableWebMvc注解。 HttpMessageConverters Spring MVC使用HttpMessageConverter接口转换HTTP请求和响应,合适的默认配置可以开箱即用,例如对象自动转换为JSON(使用Jackson库)或XML(如果Jackson XML扩展可用,否则使用JAXB),字符串默认使用UTF-8编码。 可以使用Spring Boot的HttpMessageConverters类添加或自定义转换类: importorg.springframework.boot.autoconfigure.web.HttpMessageConverters; importorg.springframework.context.annotation.*; importorg.springframework.http.converter.*; @Configuration publicclassMyConfiguration{ @Bean publicHttpMessageConverterscustomConverters(){ HttpMessageConverter<?>additional=... HttpMessageConverter<?>another=... returnnewHttpMessageConverters(additional,another); } } 上下文中出现的所有HttpMessageConverterbean都将添加到converters列表,你可以通过这种方式覆盖默认的转换器列表(converters)。 自定义JSON序列化器和反序列化器 如果使用Jackson序列化,反序列化JSON数据,你可能想编写自己的JsonSerializer和JsonDeserializer类。自定义序列化器(serializers)通常通过Module注册到Jackson,但Spring Boot提供了@JsonComponent注解这一替代方式,它能轻松的将序列化器注册为Spring Beans。 MessageCodesResolver Spring MVC有一个实现策略,用于从绑定的errors产生用来渲染错误信息的错误码:MessageCodesResolver。Spring Boot会自动为你创建该实现,只要设置spring.mvc.message-codes-resolver.format属性为PREFIX_ERROR_CODE或POSTFIX_ERROR_CODE(具体查看DefaultMessageCodesResolver.Format枚举值)。 静态内容 默认情况下,Spring Boot从classpath下的/static(/public,/resources或/META-INF/resources)文件夹,或从ServletContext根目录提供静态内容。这是通过Spring MVC的ResourceHttpRequestHandler实现的,你可以自定义WebMvcConfigurerAdapter并覆写addResourceHandlers方法来改变该行为(加载静态文件)。 在单机web应用中,容器会启动默认的servlet,并用它加载ServletContext根目录下的内容以响应那些Spring不处理的请求。大多数情况下这都不会发生(除非你修改默认的MVC配置),因为Spring总能够通过DispatcherServlet处理这些请求。 你可以设置spring.resources.staticLocations属性自定义静态资源的位置(配置一系列目录位置代替默认的值),如果你这样做,默认的欢迎页面将从自定义位置加载,所以只要这些路径中的任何地方有一个index.html,它都会成为应用的主页。 此外,除了上述标准的静态资源位置,有个例外情况是Webjars内容。任何在/webjars/**路径下的资源都将从jar文件中提供,只要它们以Webjars的格式打包。 注如果你的应用将被打包成jar,那就不要使用src/main/webapp文件夹。尽管该文件夹是通常的标准格式,但它仅在打包成war的情况下起作用,在打包成jar时,多数构建工具都会默认忽略它。 Spring Boot也支持Spring MVC提供的高级资源处理特性,可用于清除缓存的静态资源或对WebJar使用版本无感知的URLs。 如果想使用针对WebJars版本无感知的URLs(version agnostic),只需要添加webjars-locator依赖,然后声明你的Webjar。以jQuery为例,"/webjars/jquery/dist/jquery.min.js"实际为"/webjars/jquery/x.y.z/dist/jquery.min.js",x.y.z为Webjar的版本。 注如果使用JBoss,你需要声明webjars-locator-jboss-vfs依赖而不是webjars-locator,否则所有的Webjars将解析为404。 以下的配置为所有的静态资源提供一种缓存清除(cache busting)方案,实际上是将内容hash添加到URLs中,比如<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>: spring.resources.chain.strategy.content.enabled=true spring.resources.chain.strategy.content.paths=/** 注实现该功能的是ResourceUrlEncodingFilter,它在模板运行期会重写资源链接,Thymeleaf,Velocity和FreeMarker会自动配置该filter,JSP需要手动配置。其他模板引擎还没自动支持,不过你可以使用ResourceUrlProvider自定义模块宏或帮助类。 当使用比如JavaScript模块加载器动态加载资源时,重命名文件是不行的,这也是提供其他策略并能结合使用的原因。下面是一个"fixed"策略,在URL中添加一个静态version字符串而不需要改变文件名: spring.resources.chain.strategy.content.enabled=true spring.resources.chain.strategy.content.paths=/** spring.resources.chain.strategy.fixed.enabled=true spring.resources.chain.strategy.fixed.paths=/js/lib/ spring.resources.chain.strategy.fixed.version=v12 使用以上策略,JavaScript模块加载器加载"/js/lib/"下的文件时会使用一个固定的版本策略"/v12/js/lib/mymodule.js",其他资源仍旧使用内容hash的方式<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>。查看ResourceProperties获取更多支持的选项。 欢迎页面 Spring Boot支持静态和模板欢迎页面。它首先index.html在配置的静态内容位置中查找文件。如果找不到,则会查找index模板。如果找到任何一个,它将自动用作应用程序的欢迎页面。、 自定义Favicon Spring Bootfavicon.ico在配置的静态内容位置和类路径的根目录(按此顺序)中查找a。如果存在这样的文件,它会自动用作应用程序的图标。 路径匹配和内容协商 Spring MVC可以通过查看请求路径并将它匹配到应用程序中定义的映射(例如@GetMappingController方法上的注释),将传入的HTTP请求映射到处理程序。 Spring Boot选择默认禁用后缀模式匹配,这意味着请求"GET /projects/spring-boot.json"不会匹配@GetMapping("/projects/spring-boot")映射。这被认为是Spring MVC应用程序的最佳实践。此功能在过去对于没有发送正确的“Accept”请求标头的HTTP客户端来说非常有用;我们需要确保将正确的内容类型发送到客户端。如今,内容协商更可靠。 还有其他一些方法可以处理不一致地发送适当的“接受”请求标头的HTTP客户端。我们可以使用查询参数来确保类似的请求"GET /projects/spring-boot?format=json"将映射到@GetMapping("/projects/spring-boot")以下内容,而不是使用后缀匹配: spring.mvc.contentnegotiation.favor-parameter=true #我们可以更改参数名称,默认为“格式”: #spring.mvc.contentnegotiation.parameter-name=myparam #我们还可以通过以下方式注册其他文件扩展名/媒体类型: spring.mvc.contentnegotiation.media-types.markdown=text/markdown 如果您了解注意事项并仍然希望应用程序使用后缀模式匹配,则需要进行以下配置: spring.mvc.contentnegotiation.favor-path-extension=true #您也可以将该功能限制为已知扩展 #spring.mvc.pathmatch.use-registered-suffix-pattern=true #我们还可以通过以下方式注册其他文件扩展名/媒体类型: #spring.mvc.contentnegotiation.media-types.adoc=text/asciidoc ConfigurableWebBindingInitializer Spring MVC使用WebBindingInitializer为每个特殊的请求初始化相应的WebDataBinder,如果你创建自己的ConfigurableWebBindingInitializer @Bean,Spring Boot会自动配置Spring MVC使用它。 模板引擎 正如REST web服务,你也可以使用Spring MVC提供动态HTML内容。Spring MVC支持各种各样的模板技术,包括Velocity, FreeMarker和JSPs,很多其他的模板引擎也提供它们自己的Spring MVC集成。 Spring Boot为以下的模板引擎提供自动配置支持: FreeMarker Groovy Thymeleaf Velocity(1.4已不再支持) Mustache 注:由于在内嵌servlet容器中使用JSPs存在一些已知的限制,所以建议尽量不使用它们。 使用以上引擎中的任何一种,并采用默认配置,则模块会从src/main/resources/templates自动加载。 注:IntelliJ IDEA根据你运行应用的方式会对classpath进行不同的排序。在IDE里通过main方法运行应用,跟从Maven,或Gradle,或打包好的jar中运行相比会导致不同的顺序,这可能导致Spring Boot不能从classpath下成功地找到模板。如果遇到这个问题,你可以在IDE里重新对classpath进行排序,将模块的类和资源放到第一位。或者,你可以配置模块的前缀为classpath*:/templates/,这样会查找classpath下的所有模板目录。 错误处理 Spring Boot默认提供一个/error映射用来以合适的方式处理所有的错误,并将它注册为servlet容器中全局的 错误页面。对于机器客户端(相对于浏览器而言,浏览器偏重于人的行为),它会产生一个具有详细错误,HTTP状态,异常信息的JSON响应。对于浏览器客户端,它会产生一个白色标签样式(whitelabel)的错误视图,该视图将以HTML格式显示同样的数据(可以添加一个解析为'error'的View来自定义它)。为了完全替换默认的行为,你可以实现ErrorController,并注册一个该类型的bean定义,或简单地添加一个ErrorAttributes类型的bean以使用现存的机制,只是替换显示的内容。 注BasicErrorController可以作为自定义ErrorController的基类,如果你想添加对新context type的处理(默认处理text/html),这会很有帮助。你只需要继承BasicErrorController,添加一个public方法,并注解带有produces属性的@RequestMapping,然后创建该新类型的bean。 你也可以定义一个@ControllerAdvice去自定义某个特殊controller或exception类型的JSON文档: @ControllerAdvice(basePackageClasses=FooController.class) publicclassFooControllerAdviceextendsResponseEntityExceptionHandler{ @ExceptionHandler(YourException.class) @ResponseBody ResponseEntity<?>handleControllerException(HttpServletRequestrequest,Throwableex){ HttpStatusstatus=getStatus(request); returnnewResponseEntity<>(newCustomErrorType(status.value(),ex.getMessage()),status); } privateHttpStatusgetStatus(HttpServletRequestrequest){ IntegerstatusCode=(Integer)request.getAttribute("javax.servlet.error.status_code"); if(statusCode==null){ returnHttpStatus.INTERNAL_SERVER_ERROR; } returnHttpStatus.valueOf(statusCode); } } 在以上示例中,如果跟FooController相同package的某个controller抛出YourException,一个CustomerErrorType类型的POJO的json展示将代替ErrorAttributes展示。 自定义错误页面 如果想为某个给定的状态码展示一个自定义的HTML错误页面,你需要将文件添加到/error文件夹下。错误页面既可以是静态HTML(比如,任何静态资源文件夹下添加的),也可以是使用模板构建的,文件名必须是明确的状态码或一系列标签。 例如,映射404到一个静态HTML文件,你的目录结构可能如下: src/ +-main/ +-java/ |+<sourcecode> +-resources/ +-public/ +-error/ |+-404.html +-<otherpublicassets> 使用FreeMarker模板映射所有5xx错误,你需要如下的目录结构: src/ +-main/ +-java/ |+<sourcecode> +-resources/ +-templates/ +-error/ |+-5xx.ftl +-<othertemplates> 对于更复杂的映射,你可以添加实现ErrorViewResolver接口的beans: publicclassMyErrorViewResolverimplementsErrorViewResolver{ @Override publicModelAndViewresolveErrorView(HttpServletRequestrequest, HttpStatusstatus,Map<String,Object>model){ //UsetherequestorstatustooptionallyreturnaModelAndView return... } } 你也可以使用Spring MVC特性,比如@ExceptionHandler方法和@ControllerAdvice,ErrorController将处理所有未处理的异常。 映射Spring MVC以外的错误页面 对于不使用Spring MVC的应用,你可以通过ErrorPageRegistrar接口直接注册ErrorPages。该抽象直接工作于底层内嵌servlet容器,即使你没有Spring MVC的DispatcherServlet,它们仍旧可以工作。 @Bean publicErrorPageRegistrarerrorPageRegistrar(){ returnnewMyErrorPageRegistrar(); } //... privatestaticclassMyErrorPageRegistrarimplementsErrorPageRegistrar{ @Override publicvoidregisterErrorPages(ErrorPageRegistryregistry){ registry.addErrorPages(newErrorPage(HttpStatus.BAD_REQUEST,"/400")); } } 注.如果你注册一个ErrorPage,该页面需要被一个Filter处理(在一些非Spring web框架中很常见,比如Jersey,Wicket),那么该Filter需要明确注册为一个ERROR分发器(dispatcher),例如: @Bean publicFilterRegistrationBeanmyFilter(){ FilterRegistrationBeanregistration=newFilterRegistrationBean(); registration.setFilter(newMyFilter()); ... registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class)); returnregistration; } (默认的FilterRegistrationBean不包含ERRORdispatcher类型)。 WebSphere应用服务器的错误处理 当部署到一个servlet容器时,Spring Boot通过它的错误页面过滤器将带有错误状态的请求转发到恰当的错误页面。request只有在response还没提交时才能转发(forwarded)到正确的错误页面,而WebSphere应用服务器8.0及后续版本默认情况会在servlet方法成功执行后提交response,你需要设置com.ibm.ws.webcontainer.invokeFlushAfterService属性为false来关闭该行为。 Spring HATEOAS 如果正在开发基于超媒体的RESTful API,你可能需要Spring HATEOAS,而Spring Boot会为其提供自动配置,这在大多数应用中都运作良好。 自动配置取代了@EnableHypermediaSupport,只需注册一定数量的beans就能轻松构建基于超媒体的应用,这些beans包括LinkDiscoverers(客户端支持),ObjectMapper(用于将响应编排为想要的形式)。ObjectMapper可以根据spring.jackson.*属性或Jackson2ObjectMapperBuilderbean进行自定义。 通过注解@EnableHypermediaSupport,你可以控制Spring HATEOAS的配置,但这会禁用上述ObjectMapper的自定义功能。 CORS支持 跨域资源共享(CORS)是一个大多数浏览器都实现了的W3C标准,它允许你以灵活的方式指定跨域请求如何被授权,而不是采用那些不安全,性能低的方式,比如IFRAME或JSONP。 从4.2版本开始,Spring MVC对CORS提供开箱即用的支持。不用添加任何特殊配置,只需要在Spring Boot应用的controller方法上注解@CrossOrigin,并添加CORS配置。通过注册一个自定义addCorsMappings(CorsRegistry)方法的WebMvcConfigurerbean可以指定全局CORS配置: @Configuration publicclassMyConfiguration{ @Bean publicWebMvcConfigurercorsConfigurer(){ returnnewWebMvcConfigurerAdapter(){ @Override publicvoidaddCorsMappings(CorsRegistryregistry){ registry.addMapping("/api/**"); } }; } } 本文相关视频连接

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

【熵增教育】SpringBoot的配置外部化——熵增学院

在前面的课程中,我们给大家分享过SpringBoot精妙的启动配置,主要阐述的是spring的IoC容器在SpringBoot中的加载过程,并与传统项目中Spring的IoC容器加载过程进行了一个对比.我们在开发的过程中,除了IoC容器的配置之外,当然还有许多其他的配置,诸如数据库的链接信息,端口,以及项目的内部使用的一些个性化信息等.那SpringBoot是如何管理这些配置呢?我今天呢,就从以下这三个方面来给大家分享一下SpringBoot是如何管理配置信息的. 配置文件和属性获取 配置文件的名字、目录和优先级 传统的properties与YAML 1.配置文件和属性获 1.1 传统配置文件的值获取与SpringBoot中的值获取 在传统的项目里,我们的配置信息一般都写在配置文件中,然后关于spring需要的信息,我们就在spring的xml文件里引用,大略如下所示: classpath下的config里创建一个jdbc.properties jdbc.driverClassName=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/testdb?serverTimezone=UTC&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true jdbc.username=develop jdbc.password=&dT$BvYdOlH4*m9G 然后在我们的application.xml里引入我们需要的这个数据源: <?xmlversion="1.0"encoding="UTF-8"?> <beansxmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:property-placeholderlocation="classpath:config/jdbc.properties"/> <beanid="dataSource"class="com.alibaba.druid.pool.DruidDataSource"> <propertyname="driverClassName"value="${jdbc.driverClassName}"/> <propertyname="url"value="${jdbc.url}"/> <propertyname="username"value="${jdbc.username}"/> <propertyname="password"value="${jdbc.password}"/> </bean> ......其他配置 </beans> 当然除了spring的数据源信息之外,我们往往也会有一些其他的信息,比如项目返回给前端的一些报错信息等,此时我们通常的做法是使用java的原生方法去加载。如以下所示: 在classpath的config下有个webreslt.properties 0=SUCCESS 100000=参数有误 100001=AppKey不能为空 100002=Signature不能为空 100003=参数列表(paramMap)不能为空 100004=secret不能包含在参数列表中 100005=参数签名不合法 100006=手机号不能为空 100007=验证码不能为空 100008=邮件内容不能为空 100009=收件人不能为空 100010=邮件主题不能为空 200000=应用无权限 200001=应用未注册 300000=Api异常 300001=短信发送失败 300002=短信验证失败 300003=邮件发送失败 300004=短信发送超过最大条数限制 获取值的方法如下: packagecom.ailu.paas.common.utils; importorg.apache.commons.lang3.StringUtils; importjava.util.Locale; importjava.util.ResourceBundle; publicclassPropertyFileReader{ publicstaticStringgetItem(Stringkey){ returngetItem(key,""); } publicstaticStringgetItem(Stringkey,StringdefaultValue){ ResourceBundlerb=ResourceBundle.getBundle("config/webresult"); Stringvalue=""; try{ value=newString(rb.getString(key).getBytes("ISO-8859-1"),"UTF-8"); }catch(Exceptione){ e.printStackTrace(); } if(StringUtils.isEmpty(value)){ value=defaultValue; } returnvalue.trim(); } } 然后在其他的地方,我们就可以直接使用以下这样的方式去获取属性文件中的值了. Stringvalue=PropertyFileReader.getItem(key); 而在SpringBoot中呢,我们则可以使用@Component+@Value这两个组合,来快速的读取配置文件中的值, 仍然是在classpath下,我们在配置文件里写上如下配置: name="Lianmengtu" 然后我们创建一个java类,并加上@Component和@Value,如下所示: packagetop.lianmengtu.testprofile.common; importlombok.Getter; importlombok.Setter; importorg.springframework.beans.factory.annotation.Value; importorg.springframework.stereotype.Component; @Component @Getter @Setter publicclassTestProperty{ @Value("${name}") privateStringname; } 其中@Component是为了把TestProperty作为组件放入到Spring的IoC容器中,而@Value("${name}")则是为了从配置文件中取值,${name}中的name即是配置文件中的key.然后我们就可以在其他地方通过注入直接使用了: @Autowired privateTestPropertytestProperty; publicvoidtest(){ System.out.println(testProperty.getName()); } 1.2 随机值的绑定 在某些场景下,我们可能需要在项目的配置中添加一些随机值,并且这些值在我们项目启动后就自动的初始化,而SpringBoot就考虑到了这种情况,于是给我们准备了一些工具,方便我们的使用.使用情况如下: #随机字符串 secret=${random.value} #随机数 setup=${random.int} #0-10之间的随机数 range-int=${random.int[0,10]} #生成uuid uuid=${random.uuid} 获取方式和其他的属性相同,如下所示: packagetop.lianmengtu.testprofile.common; importlombok.Getter; importlombok.Setter; importorg.springframework.beans.factory.annotation.Value; importorg.springframework.stereotype.Component; @Component @Getter @Setter publicclassTestProperty{ @Value("${secret}") privateStringsecret; @Value("${setup}") privateIntegersetup; @Value("${range-int}") privateIntegerrangeInt; @Value("${uuid}") privateStringuuid; } 1.3 变量的引用与占位符 有些时候我们会在配置项中引用另一项的值,当然,是以变量的形式进行引用.如下所示: protocal=http:// domain=${protocal}ask.lianmengtu.top 这里我们看到,在springBoot中使用的变量占位符是${key}.这时候就有一个问题,因为我们现在大多数的开发环境都是maven,我们都知道maven也是支持变量占位的,我们可以在打包不同环境的时候可以激活不同的profile,然后对变量值进行替换,而我们往常在使用Maven的时候,用的变量占位符正好是${key},那此时,我们该怎么办呢?SpringBoot是不是不支持Maven的变量占位呢?我们必须要二选其一吗? 当然不是.SpringBoot也考虑到了这个问题,因此给maven占位提供了另外一个符号即@key@,如下所示: protocal=http:// domain=${protocal}ask.lianmengtu.top username=@username@ password=@password@ 然后我们就可以在我们的pom里这么写了,而当我们激活某一个profile的时候,相应的maven变量就会被替换了 <profiles> <profile> <id>dev</id> <properties> <username>dev</username> <password>dev123</password> </properties> </profile> <profile> <id>test</id> <properties> <username>test</username> <password>test123</password> </properties> </profile> </profiles> 2. yml与properties SpringBoot是除了支持properties这种方式之外,它也支持YAML这种方式,并且因为yml结构清晰,又可以继承,所以使用yml这种方式的人也越来越多了.而我就是这么对yml路转粉的. 2.1 yml结构化 yml的第一个好处是结构化,这与properties是明显的差别.这里放上两份同样的配置文件来个视觉对比,首先是properties environments.dev.url= environments.dev.name=DeveloperSetup environments.prod.url= environments.prod.name=MyCoolApp my.servers[0]=dev.example.com my.servers[1]=another.example.com 对比yml environments: dev: url:http://dev.example.com name:DeveloperSetup prod: url:http://another.example.com name:MyCoolApp my: servers: -dev.example.com -another.example.com 这里只是举个例子,所以可能这两三行大家看起来没什么感觉,但要知道在实际的项目中,我们的配置可能包含各种各样的信息,数据库的,缓存的,第三方平台的等等,那时候,如果我们还用properties,那么看着将会非常头大. 2.2 yml的继承 在我们使用配置文件的时候,尤其是分环境使用的时候,常常会碰到这么一个问题: 大多数的项目配置都一样,只有少数的不一样,此时,如果是使用properties,那么我们就只能每个文件各写一份,而在yml里,我们就不用,我们只需要将通用的那部分写到application-common.yml里,然后少量不同的,我们在分环境进行描述,application-dev.yml,application-prod.yml里,这样我们只需要激活一份文件,剩下的就会自动的进行继承和使用了,具体方式如下: application.yml app: name:"lianmengtu" country:"China" username:"melon" password:"melon123" application-dev.yml: app: username:"jacobdev" password:"dev123456" application-prod.yml app: username:"LMTprod" password:"prod456" 这样当我们在启动时,激活不同的配置时,username和password会不同,但name和country则是从默认的yml中继承过来的. 2.3 指定配置文件的名字和地址 刚刚我们提到过多种环境,配置文件之所以要区分环境,就是因为有些信息是需要保密的,无法公开.而SpringBoot则允许从外部,通过命令行的形式,对配置文件进行指定,当然也可以指定变量. 2.3.1 指定配置文件的名字 我们可以使用--spring.config.name=xxx 这样的参数形式指定配置文件的名字: $java-jarmyproject.jar--spring.config.name=myproject 2.3.2 配置指定目录下的配置文件 我们可以使用--spring.config.location=xxxxx这样的参数形式来配置指定目录下的配置文件,如下文则指定了classpath下的config目录下的test.yml java-jarmyproject.jar--spring.config.location=classpath:/config/test.yml 当然从1.x转过来的人可能更喜欢指定目录,这里要特别说明一下,如果--spring.config.location是以目录结尾的,则必须加/ 如下所示: java-jarmyproject.jar--spring.config.location=classpath:/config/ 2.3.3 配置的优先级 在我们没有明确指定文件名字的时候,springBoot会按着以下顺序进行考虑 当前目录下的config目录里的application.properties 当前目录下的application.properties classpath下的config目录下的application.properties classpath下的application.properties 当然除了这些之外,命令行也是可以传参数的,并且命令行参数的优先级是最高的. 3. 一些比较复杂的配置 使用@Value()来进行属性注入有些时候会显得比较笨重,尤其是使用多个配置或者我们的配置项是呈垂直结构化的数据时,更是这样.SpringBoot提供了另外一种方法来处理这类比较复杂的数据.这就是我们要说的@ConfigurationProperties. 首先我们有这样一个配置文件: app: name:"lianmengtu" enabled:false security: username:"jacob" password:"jacob123" roles: -USER -ADMIN 我们看到在这个配置文件里,app下有name属性,有enabled属性,其中较为特殊的是security,因为他还包含了些其他的属性,包括username,包括password,还有一个类型为String的roles集合,那么此时,我们可以对应的写成下面这个属性类 packagetop.lianmengtu.testprofile.common; importorg.springframework.boot.context.properties.ConfigurationProperties; importorg.springframework.stereotype.Component; importjava.util.ArrayList; importjava.util.Collections; importjava.util.List; @ConfigurationProperties("app") publicclassComplexProperty{ privateStringname; privatebooleanenabled; privatefinalSecuritysecurity=newSecurity(); publicStringgetName(){ returnname; } publicvoidsetName(Stringname){ this.name=name; } publicbooleanisEnabled(){ returnenabled; } publicvoidsetEnabled(booleanenabled){ this.enabled=enabled; } publicSecuritygetSecurity(){ returnsecurity; } publicstaticclassSecurity{ privateStringusername; privateStringpassword; privateList<String>roles=newArrayList<>(Collections.singleton("USER")); publicStringgetUsername(){ returnusername; } publicvoidsetUsername(Stringusername){ this.username=username; } publicStringgetPassword(){ returnpassword; } publicvoidsetPassword(Stringpassword){ this.password=password; } publicList<String>getRoles(){ returnroles; } publicvoidsetRoles(List<String>roles){ this.roles=roles; } } } 之后,我们可以在我们的service层引用它: packagetop.lianmengtu.testprofile.service.impl; importorg.springframework.beans.factory.annotation.Autowired; importorg.springframework.stereotype.Service; importtop.lianmengtu.testprofile.common.ComplexProperty; importjava.util.List; @Service publicclassPropertyService{ privatefinalComplexPropertycomplexProperty; @Autowired publicPropertyService(ComplexPropertycomplexProperty){ this.complexProperty=complexProperty; } publicStringname(){ returncomplexProperty.getName(); } publicbooleanenabled(){ returncomplexProperty.isEnabled(); } publicStringuserName(){ returncomplexProperty.getSecurity().getUsername(); } publicStringpassword(){ returncomplexProperty.getSecurity().getPassword(); } publicStringroles(){ StringBufferroles=newStringBuffer(); List<String>roleArray=complexProperty.getSecurity().getRoles(); roleArray.forEach(role->{ roles.append(role).append("----"); }); returnroles.toString(); } } 这里的构造函数注入,我们也可以换成相应的@Autowried注入.为了使这个配置生效,我们需要在Application上加上@EnableConfigurationProperties(ComplexProperty.class) packagetop.lianmengtu.testprofile; importorg.springframework.boot.SpringApplication; importorg.springframework.boot.autoconfigure.SpringBootApplication; importorg.springframework.boot.context.properties.EnableConfigurationProperties; importtop.lianmengtu.testprofile.common.ComplexProperty; @SpringBootApplication @EnableConfigurationProperties(ComplexProperty.class) publicclassApplication{ publicstaticvoidmain(String[]args){ SpringApplication.run(Application.class,args); } } 刚刚举的那种类型可以说是比较复杂的一个类型了,除了那种内嵌的形式之外,如果说我们只想得到内嵌类里面的属性或者说只有内嵌类里面有属性,则我们可以写成以下这种形式,其他的地方都不用变.这种形式我们称之为relaxed binding @ConfigurationProperties("app.security") publicclassComplexProperty{ privateStringusername; privateStringpassword; privateList<String>roles; publicStringgetUsername(){ returnusername; } publicvoidsetUsername(Stringusername){ this.username=username; } publicStringgetPassword(){ returnpassword; } publicvoidsetPassword(Stringpassword){ this.password=password; } publicList<String>getRoles(){ returnroles; } publicvoidsetRoles(List<String>roles){ this.roles=roles; } } 并且也支持map类型,配置文件如下所示,其中key可以有两种指定方式,一种是"[/key]",一种是/key: app: name:"lianmengtu" enabled:false security: username:"jacob" password:"jacob123" roles: -USER -ADMIN work: "[/position]":"CEO" "[/company]":"bat" /address:"BeiJing" 而我们的配置类则如下所示: packagetop.lianmengtu.testprofile.common; importorg.springframework.boot.context.properties.ConfigurationProperties; importjava.util.List; importjava.util.Map; @ConfigurationProperties("app.security") publicclassComplexProperty{ privateStringusername; privateStringpassword; privateList<String>roles; privateMap<String,String>work; publicStringgetUsername(){ returnusername; } publicvoidsetUsername(Stringusername){ this.username=username; } publicStringgetPassword(){ returnpassword; } publicvoidsetPassword(Stringpassword){ this.password=password; } publicList<String>getRoles(){ returnroles; } publicvoidsetRoles(List<String>roles){ this.roles=roles; } publicMap<String,String>getWork(){ returnwork; } publicvoidsetWork(Map<String,String>work){ this.work=work; } } 这两种方式都是Ok的, 总结 今天的内容,其实到这里就已经结束了,在使用配置文件的过程中,我们还碰到了一些问题,首先,我们在使用这种配置方式,无论是@Component+@Value还是后来的@ConfigurationProperties这两种方式,他都是在进入spring的时候进行初始化的,这也就意味着,如果我们没有从Spring的容器中去取我们的属性容器的话,那么我们的属性值是没有办法注入的,这一点希望大家能够注意,其次,今天只是讲了主要的几种方式,还有一些像复杂类型的属性合并,以及属性验证,这些希望大家可以研究一下,如果有不明白的,欢迎大家在论坛上提出来,我们可以一起探讨.以下是@ConfigurationProperties和@Value的一些对比: Feature @ConfigurationProperties @Value Relaxed binding Yes No Meta-data support Yes No SpELevaluation No Yes 转载请注明出处:联盟兔

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

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文件系统,支持十年生命周期更新。

WebStorm

WebStorm

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

用户登录
用户注册