四、Spring Boot与Web开发
1.SpringBoot对静态资源的映射规则
//源码
@ConfigurationProperties(
prefix = "spring.resources",
ignoreUnknownFields = false
)
public class ResourceProperties {
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
if (!registry.hasMappingForPattern("/webjars/**")) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}
}
//配置欢迎页映射
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(this.getInterceptors(mvcConversionService, mvcResourceUrlProvider));
return welcomePageHandlerMapping;
}
1)、所有/Webjars/都是从classpath:/META-INF/resources/webjars/**找资源
Webjars:以jar包的方式引入静态资源
https://www.webjars.org/
再在项目里导入
访问jquery.js
localhost:8080/webjars/jquery/3.3.1/jquery.js
2)、“/**”访问当前项目的任何资源,(静态资源的文件夹)
//源码
"classpath:/META-INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/"
"/":当前项目的根路径
先默认找resource/static的
3)、欢迎页;静态资源文件夹下的index.html页面;被"/"映射
4)、所有的/favicon.ioc都是在静态资源文件下找的
2.模板引擎
jsp、velocity、freemarker、thymeleaf
springboot推荐thymeleaf;
语法简单,功能强大
1.引入thymeleaf
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
properties标签内添加(看情况,下面的“注意版本”有提示):
<thymeleaf.version>3.0.11.RELEASE</thymeleaf.version>
<!--布局功能的支持程序 thymeleaf3主程序 layout2以上版本-->
<thymeleaf-layout-dialect.version>2.1.1</thymeleaf-layout-dialect.version>
注意版本,thymeleaf.version 3以上要对应thymeleaf-layout-dialect version2以上,我看springboot已经帮弄好了
2.thymeleaf使用语法
//源码
@ConfigurationProperties(
prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
//只要我们把HTML页面放在classpath:/templates/,thymeleaf就能自动渲染
@RequestMapping("/success")
//"classpath:/templates/success.html"
public String success(){
return "success";
}
注意版本:
<thymeleaf.version>3.0.11.RELEASE</thymeleaf.version>
使用
1.导入thymeleaf的名称空间
<html lang="en" xmlns:th="http://www.thymeleaf.org">
2.使用thymeleaf语法
@RequestMapping("/success")
//"classpath:/templates/success.html"
public String success(Map<String,Object>map){
map.put("hello", "你好");
return "success";
}
<!--th:text 将Div里面的文本内容设置为我们制定的值-->
<div th:text="${hello}">
</div>
3.语法规则
1)、th:text;改变当前文本的内容
th:任意属性; 来替换原生属性的值
具体使用
2)、表达式
Simple expressions:
Variable Expressions: ${...}
Selection Variable Expressions: *{...}
Message Expressions: #{...}
Link URL Expressions: @{...}
Fragment Expressions: ~{...}
Literals:
Text literals: 'one text' , 'Another one!' ,…
Number literals: 0 , 34 , 3.0 , 12.3 ,…
Boolean literals: true , false
Null literal: null
Literal tokens: one , sometext , main ,…
Text operations:
String concatenation: +
Literal substitutions: |The name is ${name}|
Arithmetic operations:
Binary operators: + , - , * , / , %
Minus sign (unary operator): -
Boolean operations:
Binary operators: and , or
Boolean negation (unary operator): ! , not
Comparisons and equality:
Comparators: > , < , >= , <= ( gt , lt , ge , le )
Equality operators: == , != ( eq , ne )
Conditional operators:
If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)
Special tokens:
No-Operation: _
3.Spring Web MVC 框架
https://docs.spring.io/spring-boot/docs/1.5.9.RELEASE/reference/html/boot-features-developing-web-applications.html#boot-features-spring-mvc
Spring Boot 自动配置好了 Spring MVC
以下是Spring Boot 对SpringMVC 默认配置:
- Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
- 自动配置了ViewResolver(视图解析器)
- ContentNegotiatingViewResolver组合所有视图解析器的
- 如何定制:我们可以自己给容器添加视图解析器,自动将其组合进来
- Support for serving static resources, including support for WebJars (see below).
Automatic registration of Converter, GenericConverter, Formatter beans.
Support for HttpMessageConverters (see below).
Automatic registration of MessageCodesResolver (see below).
Static index.html support.
Custom Favicon support (see below).
Automatic use of a ConfigurableWebBindingInitializer bean (see below).
If you want to keep Spring Boot MVC features, and you just want to add additional MVC configuration (interceptors, formatters, view controllers etc.) you can add your own @Configuration class of type WebMvcConfigurerAdapter, but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter or ExceptionHandlerExceptionResolver you can declare a WebMvcRegistrationsAdapter instance providing such components.
If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.
有空再看
修改默认配置
1.用户配置了,则按照用户配置,否则使用默认配置
2.
package com.atguigu.springboot.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
//@EnableWebMvc //不要接管SpringMVC
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
//单个加
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/atguigu").setViewName("success");
}
//所有组件都会一起用
//多个一起加
@Bean //加到容器中
public WebMvcConfigurer webMvcConfigurationSupport(){
WebMvcConfigurer support=new WebMvcConfigurer(){
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("/index.html").setViewName("login");
}
};
return support;
}
}
既可以使用自己的,也可以使用默认的
如果想要默认配置失效(不建议),使用@EnableWebMvc
4.国际化
1.编写国际化配置文件
再看吧
5.登录功能
开发期间禁用模板引擎,之后修改代前端代码后ctr+f9实时生效
spring.thymeleaf.cache=false
5.1拦截器做检查
登录成功后,放入session
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 addInterceptors(InterceptorRegistry registry) {
// "/**"表示拦截任意请求
//excludePathPatterns表示这些请求不需要拦截
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/","/login","/index.html","/user/login");
}
注意静态文件css放在static里面,不会被拦截
6.CRUD-员工列表
1)RestfulCRUD:CRUD满足Rest风格
普通CRUD(uri来区分操作) | RestfulCRUD | |
---|---|---|
查询 | getEmp | emp—GET |
添加 | addEmp?xxx | emp-POST |
修改 | updateEmp?id=xxx&xxx=xxx | emp/{id}—PUT |
删除 | deleteEmp?id=1 | emp/{id}—DELETE |
请求URI | 请求方式 | |
---|---|---|
查询所有员工 | emps | GET |
查询某个员工 | emp/1 | GET |
来到添加页面 | emp | GET |
添加员工 | emp | POST |
来到修改页面(查出员工信息进行回显) | emp/{id} | GET |
修改员工 | emp/{1 | DELETE |
spring.mvc.date-format=yyyy-MM-dd HH:mm
7.错误处理机制
7.1默认的错误处理机制
1.返回错误页面
2.其他的客户端返回json数据
原理参照ErrorMvcAutoConfigration
给容器中添加了以下组件
1.DefaultErrorAttributes
2.BasicErrorController
3.ErrorPageCustomizer
4.DefaultErrorViewResolver
一旦出现错误:ErrorPageCustomizer就会生效;就会来到“/error”请求,之后BasicErrorController生效,处理默认“/error”请求
7.2定制错误响应
7.2.1定制错误页面:
当有模板引擎时
error/状态码 创建error文件夹,编写状态码.htlm
一个一个匹配太复杂用 4XX
没有有模板引擎时
放在静态文件夹下
7.2.2定制错误返回JSON
exception包下:
public class UserNotExistException extends RuntimeException{
public UserNotExistException(){
super("用户不存在");
}
}
之后 在出错的地方:
throw new UserNotExistException();
MyExceptionHandler设置要返回的json数据
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class MyExceptionHandler {
//方法1:浏览器和客户端返回的都是json数据
// @ResponseBody //表示返回json数据
// @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;
// }
// 方法2:浏览器和客户端返回的都是json数据
//缺点:自定义的map.put("code", "user.notexist");无法生效
// @ExceptionHandler(UserNotExistException.class)
// public String handleException(Exception e, HttpServletRequest request){
// Map<String,Object> map = new HashMap<>();
// //社hi在自己的状态码
// request.setAttribute("javax.servlet.error.status_code", 400);
// map.put("code", "user.notexist");
// map.put("message", e.getMessage());
// //转发到/error,这样会自适应响应,
// return "forward:/error";
// }
@ExceptionHandler(UserNotExistException.class)
public String handleException(Exception e, HttpServletRequest request){
Map<String,Object> map = new HashMap<>();
//在自己的状态码
request.setAttribute("javax.servlet.error.status_code", 400);
map.put("code", "user.notexist");
map.put("message", e.getMessage());
request.setAttribute("ext", map);
//转发到/error,这样会自适应响应,
return "forward:/error";
}
添加自己定义的ErrorAttributes
import org.springframework.web.context.request.WebRequest;
import java.util.Map;
//给容器添加自己定义的ErrorAttributes
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map<String, Object> map= super.getErrorAttributes(webRequest, includeStackTrace);
map.put("company", "atguigu");
//我们异常处理器携带的数据
Map<String, Object>ext=(Map<String, Object>)webRequest.getAttribute("ext", 0);
map.put("ext", ext);
return map;
}
}