打开application.yaml文件,就可以看到Halo的配置内容,笨鸟有笨的办法,我们可以一点点的开始分析,先来看看关于内置服务器undertow的配置
server:
port: 8090
use-forward-headers: true
undertow:
io-threads: 2
worker-threads: 36
buffer-size: 1024
directBuffers: true
servlet:
session:
timeout: 86400s
这些都是常规的设置,什么端口号啊,session失效时间,还有有关undertow的io线程数,阻塞任务线程池等等。这些配置如果不懂呢网上搜一搜就知道了。当然还有这个springboot内嵌服务器啊,如何将默认的tomcat转换为undertow也是需要自己慢慢弄明白的,如果不会呢,就可以看看我写的博客《springboot配置undertow容器》,不过呢我是用springboot2.1.1做的demo,假如你比我的版本高的话就可以不用博客里的最后一步,直接将tomcat依赖排除,加上undertow的依赖,然后配置文件写上配置就完事了,完全不用再配置一个ServletWebServerFactory,还是相当简单的。
接下来就是H2数据库的配置了,如图所示
spring:
output:
ansi:
enabled: always
datasource:
type: com.zaxxer.hikari.HikariDataSource
# H2database 配置
driver-class-name: org.h2.Driver
url: jdbc:h2:file:./halo/halo
username: admin
password: 123456
#MySql配置
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://127.0.0.1:3306/halodb?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
# username: root
# password: 123456
h2:
console:
settings:
web-allow-others: true
path: /h2-console
enabled: true
jpa:
hibernate:
ddl-auto: update
show-sql: false
作者用的是H2数据库并没有使用mysql,当然它也是可以支持mysql的,mysql我们已经熟悉了,所以我们可以试试这个陌生的H2数据库是怎么使用的。这些也是很常规的配置,我相信大家肯定看得懂,从上到下分别是,日志彩色显示,连接池(应该是连接池吧),驱动,url,用户名,密码,还有有关H2的配置,Jpa的配置啥的,mysql配置已经注释掉了。H2配置里的path属性表示项目启动之后就可以用这个路径来访问数据库,是的,它是通过浏览器访问数据库的,不过呢关系型数据库都差不多,都很简单,大家看一看就明白了。还有就是这个url地址,刚开始在file:后边是~符号,项目一启动就会在C盘用户目录下创建数据库文件,于是呢我就把它改到了项目根目录下./表示项目的根目录,如图所示
这个就是你的数据库了。
接下来就是有关Freemarker的配置,如果你想学就研究研究。不过呢现在都流行前后端分离的模式,所以我不打算研究它。
然后呢就是上传文件的设置,国际化的设置,日志的设置
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
# 多语言资源文件路径
messages:
basename: i18n/messages
logging:
file: ./logs/log.log
关于springboot实现国际化也是非常的简单,如果没有做过,可以网上搜一搜,都有详细的教程,只要照着做就行了,当然要是有人像我一样不老老实实的照着做,出现问题了,可以参考我的这篇文章,是不是出现了和我一样的问题——springboot国际化
接下来我们来看看Halo是如何实现国际化的,我们先看看这个i18n文件夹里的properties文件,看着就不简单,500行左右,也就是近500个词作者都做了国际化翻译,要是让我来,光是给变量起名字都费死劲了。这里我还得说一句,看看人家的包名
看着就很好,一眼下去就知道哪个包是干什么的,我们想要找国际化设置,自然是在config包里面找
这里面就两个类,一看类名就知道是在哪个类里边,不得不说一句,我们要学学人家是怎么起名字的,光看类名就知道这个类是干啥的。我也是在几个月前才开始尽量起比较符合规范的名字,不要怕名字长,没关系,名字长不长的无所谓,我们要的是望文知意。点开这个类,往下翻,就能看到有关国际化的设置
/**
* 国际化设置
*
* @return LocaleResolver
*/
@Bean
public LocaleResolver localeResolver() {
final SessionLocaleResolver slr = new SessionLocaleResolver();
slr.setDefaultLocale(Locale.CHINA);
return slr;
}
/**
* 国际化参数拦截器
*
* @return LocaleChangeInterceptor
*/
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
final LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
lci.setParamName("lang");
return lci;
}
作者实现国际化的方式跟我的略有不同,使用的是SessionLocaleResolver和LocaleChangeInterceptor相结合的方式,不过作者为什么要将这两个对象用final修饰呢,难道是要把它变成唯一不可变的吗?但是如果把它交给spring来管理,默认的就是单例模式,不用final也可以吧。这个问题先存着,或许等我有项目经验了就明白了。言归正传,接下来就是注册拦截器了,也是在这个类里边,最上边的这个方法
/**
* 注册拦截器
*
* @param registry registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/admin.*")
.addPathPatterns("/admin/**")
.addPathPatterns("/backup/**")
.excludePathPatterns("/admin/login")
.excludePathPatterns("/admin/getLogin")
.excludePathPatterns("/static/**");
registry.addInterceptor(installInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/install")
.excludePathPatterns("/install/do")
.excludePathPatterns("/static/**");
registry.addInterceptor(apiInterceptor)
.addPathPatterns("/api/**");
registry.addInterceptor(localeInterceptor)
.addPathPatterns("/admin.*")
.addPathPatterns("/admin/**")
.addPathPatterns("/install");
registry.addInterceptor(localeChangeInterceptor())
.addPathPatterns("/install");
}
我们看到,它注册了不少拦截器,其中有两个关于国际化的,就是最后两个,它居然有两个拦截器,刚刚我们只是看到了其中一个LocaleChangeInterceptor用来拦截参数,通过参数来改变语言,接下来看看这个LocaleInterceptor主要是干啥的。看看有这么多拦截器就知道,作者肯定有一个包专门放拦截器,就是在web包下。我们打开这个拦截器类,也没几行代码,看着一行怪长,还没有写注释,但是我们耐心一读就明白了。这样,我手动加上注释再把代码贴出来。
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//先从session中找到Locale
final Object attribute = request.getSession().getAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME);
//判断Locale是否存在,如果有就直接放行
if (null != attribute) {
return true;
}
/*
* 判断博客语言设置是不是en_US,如果是的话就在session中保存一个英文的Locale
* 如果不是就存一个中文的Locale
*/
if (StrUtil.equals(LocaleEnum.EN_US.getValue(), OPTIONS.get(BlogPropertiesEnum.BLOG_LOCALE.getProp()))) {
request.getSession().setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, new Locale("en", "US"));
} else {
request.getSession().setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, new Locale("zh", "CN"));
}
return true;
}
这里作者又一次用了final,我依旧不甚理解为什么要用final修饰,而且好多地方都用了final,也可能是我经验少,没写过什么项目,到现在我写代码几乎没有用过final修饰,所以看到了这个final就觉得作者用了好多次。好了,回到正题,我们还是说一说这个国际化的问题,我们知道,国际化需要用Locale来决定用英文还是中文或者是其他语言,这个SessionLocaleResolver应该是将这个Locale保存到了session中,所以先要看看session中有没有这个Locale,如果有的话直接放行,直接用session中的Locale就行了,如果没有的话,自然是新建一个,怎么建呢,就是接下来的代码,先看看博客设置选项里是不是英文的,如果不是就建一个中文的。或许大家会有疑问,每个变量这么长都是啥意思?这个问题不要担心,作者已经做了注释,只要选中这个变量,然后快捷键ctrl+q就会显示出来这个变量的意思。这些基本上就是Halo的国际化操作了,虽然简单,但是也是值得一看。