源码地址:https://github.com/877148107/scms_admin/tree/master/scms_learn_thymeleaf
参考文档:https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/reference/html/spring-boot-features.html#boot-features-internationalization
#配置国际化资源的配置文件路径+名称
spring.messages.basename=i18n.login
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(name = AbstractApplicationContext.MESSAGE_SOURCE_BEAN_NAME, search = SearchStrategy.CURRENT)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Conditional(ResourceBundleCondition.class)
@EnableConfigurationProperties
public class MessageSourceAutoConfiguration {
private static final Resource[] NO_RESOURCES = {};
@Bean
@ConfigurationProperties(prefix = "spring.messages")
public MessageSourceProperties messageSourceProperties() {
return new MessageSourceProperties();
}
Signin Template for Bootstrap
SpringMvc自动配置中添加了国际化Locale(区域信息对象),LocaleResolver(获取区域信息对象)
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
......
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
if (this.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
}
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
}
}
自己重写获取区域信息对象,那么自动配置中的就会失效
package com.wmy.scms.comment;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.LocaleResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
/**
* @ClassName: MyLocaleResolver
* =================================================
* @Description: 区域信息
* =================================================
* CreateInfo:
* @Author: William.Wangmy
* @Email: [email protected]
* @CreateDate: 2020/1/7 23:08
* @Version: V1.0
*/
public class MyLocaleResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest request) {
String l = request.getParameter("l");
Locale locale = Locale.getDefault();
if (!StringUtils.isEmpty(l)) {
String[] s = l.split("_");
locale = new Locale(s[0],s[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
}
}
效果
URI: /资源名称/资源标识 HTTP请求方式区分对资源CRUD操作
普通CRUD(uri来区分操作) | RestfulCRUD | |
---|---|---|
查询 | getEmp | emp---GET |
添加 | addEmp?xxx | emp---POST |
修改 | updateEmp?id=xxx&xxx=xx | emp/{id}---PUT |
删除 | deleteEmp?id=1 | emp/{id}---DELETE |
[[${emp.lastName}]]
编辑
/**
* 修改页面
* @param id
* @param model
* @return
*/
@GetMapping("/emp/{id}")
public String toEditPage(@PathVariable("id") Integer id,Model model){
Employee employee = employeeDao.get(id);
model.addAttribute("emp",employee);
//页面要显示所有的部门列表
Collection departments = departmentDao.getDepartments();
model.addAttribute("depts",departments);
//回到修改页面(add是一个修改添加二合一的页面);
return "emp/add";
}
/**
* 新增
* @param employee
* @return
*/
@PostMapping("/emp")
public String addEmp(Employee employee){
//来到员工列表页面
System.out.println("保存的员工信息:"+employee);
//保存员工
employeeDao.save(employee);
// redirect: 表示重定向到一个地址 /代表当前项目路径
// forward: 表示转发到一个地址
return "redirect:/emps";
}
/**
* 修改信息
* @param employee
* @return
*/
@PutMapping("/emp")
public String updateEmployee(Employee employee){
System.out.println("修改的员工数据:"+employee);
employeeDao.save(employee);
return "redirect:/emps";
}
/**
* 员工删除
*/
@DeleteMapping("/emp/{id}")
public String deleteEmployee(@PathVariable("id") Integer id){
employeeDao.delete(id);
return "redirect:/emps";
}
错误信息自动配置给容器中添加了一下组件:
1.DefaultErrorAttributes
页面共享信息
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DefaultErrorAttributes implements ErrorAttributes, HandlerExceptionResolver, Ordered {
@Override
public Map getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map errorAttributes = new LinkedHashMap<>();
errorAttributes.put("timestamp", new Date());
addStatus(errorAttributes, webRequest);
addErrorDetails(errorAttributes, webRequest, includeStackTrace);
addPath(errorAttributes, webRequest);
return errorAttributes;
}
timestamp:时间戳
status:状态码
error:错误提示
exception:异常对象
message:异常消息
errors:JSR303数据校验的错误都在这里
以上信息都可以在页面获取到
2.BasicErrorController
第一个方法产生HTML数据、第二个方法产生JSON数据
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
HttpStatus status = getStatus(request);
Map model = Collections
.unmodifiableMap(getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
//跳转到那个错误页面
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
}
@RequestMapping
public ResponseEntity
3.ErrorPageCustomizer
private static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered {
private final ServerProperties properties;
private final DispatcherServletPath dispatcherServletPath;
protected ErrorPageCustomizer(ServerProperties properties, DispatcherServletPath dispatcherServletPath) {
this.properties = properties;
this.dispatcherServletPath = dispatcherServletPath;
}
@Override
public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
ErrorPage errorPage = new ErrorPage(
this.dispatcherServletPath.getRelativePath(this.properties.getError().getPath()));
errorPageRegistry.addErrorPages(errorPage);
}
系统出现错误后来到error请求进行处理, BasicErrorController
public class ErrorProperties {
/**
* Path of the error controller.
*/
@Value("${error.path:/error}")
private String path = "/error";
4.DefaultErrorViewResolver
系统默认是找工程目录下error下的错误代码页面,比如error/404.html
模板引擎可以解析的就返回对应的页面,不能解析就去找静态资源下的页面error/404.html
public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {
private static final Map SERIES_VIEWS;
static {
Map views = new EnumMap<>(Series.class);
views.put(Series.CLIENT_ERROR, "4xx");
views.put(Series.SERVER_ERROR, "5xx");
SERIES_VIEWS = Collections.unmodifiableMap(views);
}
@Override
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map model) {
ModelAndView modelAndView = resolve(String.valueOf(status.value()), model);
if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
}
return modelAndView;
}
private ModelAndView resolve(String viewName, Map model) {
String errorViewName = "error/" + viewName;
TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName,
this.applicationContext);
if (provider != null) {
return new ModelAndView(errorViewName, model);
}
return resolveResource(errorViewName, model);
}
private ModelAndView resolveResource(String viewName, Map model) {
for (String location : this.resourceProperties.getStaticLocations()) {
try {
Resource resource = this.applicationContext.getResource(location);
resource = resource.createRelative(viewName + ".html");
if (resource.exists()) {
return new ModelAndView(new HtmlResourceView(resource), model);
}
}
catch (Exception ex) {
}
}
return null;
}
错误处理规则:
1.系统当中出现了错误信息4xx、5xx等错误信息ErrorPageCustomizer组件就会生效
2.出现错误后系统会发出error请求BasicErrorController进行处理,错误页面的跳转由默认的错误页面解析器处理DefaultErrorViewResolver
protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status,
Map model) {
for (ErrorViewResolver resolver : this.errorViewResolvers) {
ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);
if (modelAndView != null) {
return modelAndView;
}
}
return null;
}