目标:开发一个spingboot的web项目,项目地址:点我
首先导入实体类和dao层,然后导入静态资源到static文件夹下,页面放入templates文件夹下,项目目录如下所示
1. 默认访问首页
我们想将login.html作为默认的首页,有两种方法
- 在控制类中使用
RequestMapping("/login")
构建视图映射 - 在配置类中添加视图控制器从而构建视图映射,springboot主要采取这种方法
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/santiago").setViewName("success");
}
//所有WebMvcConfigurer会一起起作用
@Bean //将组件注册在容器中
public WebMvcConfigurer webMvcConfigurer(){
WebMvcConfigurer adapter = new WebMvcConfigurer() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("/index.html").setViewName("login");
}
};
return adapter;
}
}
然后配置login.html,使用thymeleaf语法
2. 国际化
如果在SpringMVC中要使用国际化,需要以下3步:
- 编写国际化配置文件
- 使用ResourceBundleMessageSource管理国际化资源文件
- 在页面使用fmt:message取出国际化内容
在SpringBoot中,步骤就简单多了
2.1 编写国际化配置文件
在resources根目录下新建一个文件夹i18n,在里面建立三个文件login.properties、login_zh_CN.properties、login_en_US.properties,分别代表默认,中文,英文显示的login页面。
接下来根据login页面中的元素,编写国际化文件
打开login_en_US.properties或者login_zh_CN.properties,切换到Resource Bundle视图,可以方便地编辑三个文件
2.2 管理国际化资源文件
这里springboot的MessageSourceAutoConfiguration
已经帮我们配置好了
public class MessageSourceAutoConfiguration {
@Bean
@ConfigurationProperties(
prefix = "spring.messages"
)
//设置国际化资源文件的基础名(去掉语言国家代码的)
@Bean
public MessageSource messageSource(MessageSourceProperties properties) {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
if (StringUtils.hasText(properties.getBasename())) { messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(properties.getBasename())));
}
......
}
public class MessageSourceProperties {
private String basename = "messages";
spingboot设置国际化配置文件的基础名为message
,我们的国际化配置文件可以直接放在类路径下叫messages.properties
,但是根据第一步我们自己写的国际化配置文件,要重新制定国际化配置文件的基础名
在application.properties文件中添加如下代码
spring.messages.basename=i18n.login
2.3 去页面获取国际化的值
根据thymeleaf,获取国际化值的方法时使用#{*}
2.4 文件编码
最好按以下方式设置,相当于修改了项目的默认文件编码,包括当前项目
2.5 测试
使用Chrome浏览器,选择浏览器语言为中文,且移至首位。之所以将其放在第一个位置,是因为每发一个请求的时候,请求头里的Accept-Language
属性的第一个值为zh_CN
首页显示如下
将Chrome浏览器的语言设置为英文(美国),且移到顶部
首页显示为
2.6 点击切换语言
页面底部有个中英文按钮,我们如何使用点击的方式来切换浏览器的语言呢,这就要了解一下国际化的原理。
国际化的配置主要是根据Locale
(区域信息对象);LocaleResolver
(获取区域信息对象)
WebMvcAutoConfiguration
类中有以下方法可以获取locale值
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(
prefix = "spring.mvc",
name = {"locale"}
)
public LocaleResolver localeResolver() {
if (this.mvcProperties.getLocaleResolver() == org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
} else {
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
}
}
这个locale值对应着请求头里的Accept-Language
属性的第一个值,当项目中没有用户建立的LocaleResolver时会使用这个默认的LocaleResolver
,于是我们创建一个自己的MyLocaleResolver
,并将其添加进容器
public class MyLocaleResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest request) {
String l = request.getParameter("l");
Locale locale = Locale.getDefault();
if(!StringUtils.isEmpty(l)){
//从请求域中获取属性l的值,将其以"_"分开,split[0]代表语言,split[1]代表地区
String[] split = l.split("_");
locale = new Locale(split[0],split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
}
}
在配置类MyMvcConfig中将自己创建的LocaleResolver添加进容器,
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
对login.html做如下修改,将l值传入请求域
<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
这样,点击页面上的中文或英文标签就能切换语言。
3. 配置登录页面
-
添加LoginController,设置admin以及123456分别为用户名和密码,添加错误登录信息提示
@Controller public class LoginController { @PostMapping(value = "/user/login") // @RequestMapping(value = "/user/login", method = RequestMethod.POST) public String login(@RequestParam("username") String username, @RequestParam("password") String password, Map<String, Object> map){ if(!StringUtils.isEmpty(username) && "123456".equals(password)){ //登录成功 return "dashboard"; }else{ //登录失败 map.put("msg", "用户名密码错误"); return "login"; } } }
-
开发期间模板引擎页面修改以后,要实时生效
首先在application.properties禁用缓存
# 禁用缓存 spring.thymeleaf.cache=false
每当页面重新编辑以后,按
Ctrl+F9
重新编译 -
在login.html中修改form表单中的action请求路径
<form class="form-signin" th:action="@{/user/login}" th:method="post">
-
在login页面中添加a标签提示错误信息
<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1> <!-- 判断--> <p style="color:red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p> <label class="sr-only" th:text="#{login.username}">Username</label>
如果msg为空,不显示错误信息。
-
登录成功后,进入dashboard.html,刷新页面的时候,浏览器会提示要重新提交表单。为了防止表单的重复提交,我们修改LoginController,重定向到dashboard页面,在配置类中添加请求映射“/main.html”
MyMvcConfig.java
@Bean //将组件注册在容器中 public WebMvcConfigurer webMvcConfigurer(){ WebMvcConfigurer adapter = new WebMvcConfigurer() { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("login"); registry.addViewController("/index.html").setViewName("login"); registry.addViewController("/main.html").setViewName("dashboard"); } }; return adapter; }
LoginController
public String login(@RequestParam("username") String username, @RequestParam("password") String password, Map<String, Object> map){ if(!StringUtils.isEmpty(username) && "123456".equals(password)){ //登录成功 return "redirect:/main.html"; }else{ //登录失败 map.put("msg", "用户名密码错误"); return "login"; }
-
上一步配置好以后,可以通过请求路径
localhost:8080/main.html
直接访问dashboard,这就失去了登录页面的意义。我们可以配置拦截器,拦截请求查看是否已经登录,如果已经登录可以通过localhost:8080/main.html
直接访问dashboard。首先修改LoginController,往session添加已登录的用户名
loginUser
public String login(@RequestParam("username") String username, @RequestParam("password") String password, Map<String, Object> map, HttpSession session){ if(!StringUtils.isEmpty(username) && "123456".equals(password)){ //登录成功 session.setAttribute("loginUser", username); return "redirect:/main.html"; // return "dashboard"; }else{
创建拦截器
component.LoginHandlerInterceptor
做登录检查public class LoginHandlerInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object user = request.getSession().getAttribute("loginUser"); if(user == null){ //未登录 request.setAttribute("msg", "没有权限,请先登录"); request.getRequestDispatcher("/index.html").forward(request, response); return false; }else{ //已登录,放行 return true; } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
之后在配置类中把拦截器添加进去,拦截所有请求
/**
,然后把访问登录页面的请求/
、/index.html
、/user/login
排除掉。对于如css等静态资源的访问,SpringBoot已经做好了配置,我们不用管。@Bean //将组件注册在容器中 public WebMvcConfigurer webMvcConfigurer(){ WebMvcConfigurer adapter = new WebMvcConfigurer() { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("login"); registry.addViewController("/index.html").setViewName("login"); registry.addViewController("/main.html").setViewName("dashboard"); } //注册拦截器 @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**") .excludePathPatterns("/index.html", "/", "/user/login"); } }; return adapter; }
-
修改dashboard.html,使用
[[${session.loginUser}]]
在该页面显示登录的用户名<body> <nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0"> <a class="navbar-brand col-sm-3 col-md-2 mr-0" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">[[${session.loginUser}]]</a> <input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search"> ......
-
使用thymeleaf方式修改dashboard.html的代码。