SpringBoot对静态资源的映射规则
(1)、所有 /webjars/** ,都去 classpath:/META-INF/resources/webjars/ 找资源
webjars:以jar包的方式引入静态资源;
localhost:8080/webjars/jquery/3.3.1/jquery.js
<!--引入jquery-webjar 在访问的时候只需要写webjars下面资源的名称即可-->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1</version>
</dependency>
(2)、“/**” 访问当前项目的任何资源,都去(静态资源的文件夹)找映射
“classpath:/META‐INF/resources/”,
“classpath:/resources/”,
“classpath:/static/”,
“classpath:/public/”
“/”:当前项目的根路径
(3)、欢迎页; 静态资源文件夹下的所有index.html页面;被"/**"映射;
(4)、所有的 **/favicon.ico 都是在静态资源文件下找;
模板引擎
国际化
步骤:
(1)、编写国际化配置文件,抽取页面需要显示的国际化消息
(2)、SpringBoot自动配置好了管理国际化资源文件的组件;
(3)、去页面获取国际化的值;
<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>
效果:根据浏览器语言设置的信息切换了国际化
原理:
国际化Locale(区域信息对象);LocaleResolver(获取区域信息对象);
package com.atguigu.springboot.component;
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;
/**
* 可以在连接上携带区域信息
*/
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[] split = l.split("_");
locale = new Locale(split[0], split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
}
}
并将MyLocaleResolver 交给spring管理
注册为bean
//WebMvcConfigurer
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
默认的就是根据请求头带来的区域信息获取Locale进行国际化
(4)、点击链接切换国际化
登录
开发期间模板引擎页面修改以后,要实时生效
(1)、禁用模板引擎的缓存
#禁用缓存
spring.thymeleaf.cache=false
(2)、页面修改完成以后ctrl+f9:重新编译;
拦截器进行登陆检查
拦截器
实现HandlerInterceptor接口
package com.atguigu.springboot.component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 登录检查
*/
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 {
}
}
注册拦截器
//注册拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//super.addInterceptors(registry);
//静态资源; *.css , *.js
//SpringBoot已经做好了静态资源映射
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/index.html","/","/user/login");
}
错误处理机制
SpringBoot默认的错误处理机制
默认效果:
(1).浏览器,返回一个默认的错误页面
如何定制错误响应
A.如何定制错误的页面;
i 、 有模板引擎的情况下;error/状态码; 【将错误页面命名为 错误状态码.html 放在模板引擎文件夹里面的error文件夹下】,发生此状态码的错误就会来到 对应的页面;
我们可以使用4xx和5xx作为错误页面的文件名来匹配这种类型的所有错误,精确优先(优先寻找精确的状态码.html);
页面能获取的信息;
timestamp:时间戳
status:状态码
error:错误提示
exception:异常对象
message:异常消息
errors:JSR303数据校验的错误都在这里
ii、 没有模板引擎(模板引擎找不到这个错误页面),静态资源文件夹下找;
iii、 以上都没有错误页面,就是默认来到SpringBoot默认的错误提示页面;
B. 如何定制错误的json数据
i、 自定义异常处理&返回定制json数据;
写个异常处理器
@ControllerAdvice
public class MyExceptionHandler {
//1、浏览器客户端返回的都是json
/*@ResponseBody
@ExceptionHandler(UserNotExistException.class)
public Map<String,Object> handleException(Exception e){
Map<String,Object> map = new HashMap<>();
map.put("code","user.notexist");
map.put("message",e.getMessage());
return map;
}*/
//自适应
@ExceptionHandler(UserNotExistException.class)
public String handleException(Exception e, HttpServletRequest request){
Map<String,Object> map = new HashMap<>();
//传入我们自己的错误状态码 4xx 5xx
/**
* Integer statusCode = (Integer) request
.getAttribute("javax.servlet.error.status_code");
*/
request.setAttribute("javax.servlet.error.status_code",500);
map.put("code","user.notexist");
map.put("message","用户出错啦");
request.setAttribute("ext",map);
//转发到/error
return "forward:/error";
}
}
C. 将我们的定制数据携带出去
//给容器中加入我们自己定义的ErrorAttributes
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
//返回值的map就是页面和json能获取的所有字段
@Override
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
Map<String, Object> map = super.getErrorAttributes(requestAttributes, includeStackTrace);
map.put("company","atguigu");
//我们的异常处理器携带的数据
Map<String,Object> ext = (Map<String, Object>) requestAttributes.getAttribute("ext", 0);
map.put("ext",ext);
return map;
}
}
配置嵌入式Servlet容器
SpringBoot默认使用Tomcat作为嵌入式的Servlet容器;
问题?
(1)、如何定制和修改Servlet容器的相关配置;
两种方式:
1.配置文件
server.port=8081
server.context‐path=/crud
server.tomcat.uri‐encoding=UTF‐8
#通用的Servlet容器设置
server.xxx
#Tomcat的设置
server.tomcat.xxx
2、编写一个EmbeddedServletContainerCustomizer:嵌入式的Servlet容器的定制器;来修改Servlet容器的配置
@Bean //一定要将这个定制器加入到容器中
public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(){
return new EmbeddedServletContainerCustomizer() {
//定制嵌入式的Servlet容器相关的规则
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.setPort(8083);
}
};
}
(2)、注册Servlet三大组件【Servlet、Filter、Listener】
由于SpringBoot默认是以jar包的方式启动嵌入式的Servlet容器来启动SpringBoot的web应用,没有web.xml文
件。
注册三大组件用以下方式:
//注册三大组件
@Bean
public ServletRegistrationBean myServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(),"/myServlet");
registrationBean.setLoadOnStartup(1);
System.out.println("111111");
return registrationBean;
}
@Bean
public FilterRegistrationBean myFilter(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new MyFilter());
registrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet"));
System.out.println("222222");
return registrationBean;
}
@Bean
public ServletListenerRegistrationBean myListener(){
ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener());
System.out.println("33333");
return registrationBean;
}
MyServelt
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Hello MyServlet");
}
}
MyFilter
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("MyFilter process...");
chain.doFilter(request,response);
}
@Override
public void destroy() {
}
}
MyListener
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("contextInitialized...web应用启动");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("contextDestroyed...当前web项目销毁");
}
}