首页IT科技springboot thymeleaf教程(SpringBoot)

springboot thymeleaf教程(SpringBoot)

时间2025-09-19 18:08:10分类IT科技浏览4850
导读:SpringBoot 文章来源于:雷神:https://www.bilibili.com/video/BV19K4y1L7MT/?spm_id_from=333.337.search-card.all.click&vd_source=a9bff059910348f08db3690eefbeacbe...

SpringBoot 文章来源于:雷神:https://www.bilibili.com/video/BV19K4y1L7MT/?spm_id_from=333.337.search-card.all.click&vd_source=a9bff059910348f08db3690eefbeacbe

特点:

依赖管理 父项目用来做依赖管理:利用maven的依赖传递原则 其他都不用写明版本号 可以在当前项目里面重写配置             ,利用的是 maven的 就近依赖原则

自动配置 导入Tomcat依赖后

自动配好Web常见功能                        ,如:字符编码问题

默认的包结构        ,用于注解扫描

主程序所在包(启动类所在包)及其下面的所有子包里面的组件都会被默认扫描进来

所以无需以前的包扫描配置

如果想要改变扫描路径         ,

@SpringBootApplication(scanBasePackages="com.atguigu")或者@ComponentScan 指定扫描路径

各种配置拥有默认值

默认配置最终都是映射到某个类的属性上                       ,如:MultipartProperties

配置文件的值最终会绑定到对应的类上            ,这些类会在容器中创建对象             。所以用到这些值的时候      ,SpringBoot底层会拿到这些类的对象                      ,提取出值                ,之后绑定   ,关于如何绑定                     ,要讨论

按需加载所有自动配置项

非常多的starter

引入了哪些场景这个场景的自动配置才会开启                    ,例如:web场景就只有web

SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面

自动配置,spring-boot-autoconfigure                        。包里源码标红                 ,表示依赖的其它的包未导入                        ,导入其依赖的包即可使用

@SpringBootApplication

标识启动类        。有下三个重要注解标识

@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication{}====================== 1.@SpringBootConfiguration

@Configuration         。代表当前是一个配置类

2.@ComponentScan

指定扫描哪些    ,Spring注解;

3.@EnableAutoConfiguration

该注解有两个注解进行标识

@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration {}

AutoConfigurationPackage是导入你自己创建的Bean             ,比如controller啥的                        ,下面的Import是导入第三方的组件        ,比如DispatcherServlet啥的                       。

所以说本项目中的 类的优先级高于自动配置starter中的bean创建

1.@AutoConfigurationPackage

自动配置包?指定了默认的包规则

2.@Import(AutoConfigurationImportSelector.class)

有选择的导入

@ConditionalOnBean(Value)

标注在类和方法上            。作用         ,如果ioc容器中有value值的Bean才能将其标注的方法或者类生效

@ConditionalOnMissingBean(value)

标注在类和方法上                       ,作用与上一个相反            ,如果ioc容器中没有value值的Bean才能将其标注的方法或者类生效

@ImportResource(value="classpath:")

作用在类上      ,将配置文件导入      。

@EanalbeConfigurationProperties({Car.class})

作用在配置类上                      ,作用1.开启Car这个类的配置绑定功能(可以实现类属性绑定yml自定义值)                      。2.把Car这个组件加入ioc容器

类属性绑定yml中的自定义值

1. @Component + @ConfigurationProperties(prefix="自定义前缀")

只有在容器中的组件                ,才会拥有SpringBoot提供的强大功能   ,所以要加上@Component注解

2. @EnableConfigurationProperties(类.class) + @ConfigurationProperties(prefix)

@EnableConfigurationProperties 一定要写在配置类

定制化mvc

1                、使用Servlet API

@ServletComponentScan(basePackages = "com.atguigu.admin") :指定原生Servlet组件都放在那里

请求不发送到DispatchServlet                     ,不经过dispatcher方法                    ,不过拦截器

拦截器是DispatcherServlet类中dodispatch()方法中的,这里DispatcherServlet的没走                 ,走的是我们定义 的Servlet,所以拦截器就不会生效.

Servlet 是规范之一                        ,只是框架在底层帮我们实现了

原生不经过那一系列框架    ,效率会更高

原因很简单             ,就是springmvc底层实际上就是一个大型的servlet, 而他的urlpatterns为 /                 。所以当请求/.my时

会精确匹配到自定义的servlet, 不会经过spring.

@WebServlet(urlPatterns = "/my"):效果:直接响应                        ,没有经过Spring的拦截器?

@WebFilter(urlPatterns={"/css/*","/images/*"}) @WebFilter(filterName = "loginCheckFilter",urlPatterns = "/*")public class LoginCheckFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse;​ //1                     、获取本次请求的URI String requestURI = request.getRequestURI();// /backend/index.html //过滤器放行 filterChain.doFilter(request,response); //直接return则表示拦截 return;}

@WebListener

东西太多看别个博客吧   。

https://blog.csdn.net/weixin_41924879/article/details/101175659

2        、使用RegistrationBean

ServletRegistrationBean`, `FilterRegistrationBean`, and `ServletListenerRegistrationBean //filter用于字符过滤        ,listener用于初始化作用域数据         ,interceptor用于拦截请求@Configuration()public class MyRegistConfig {​ @Bean public ServletRegistrationBean myServlet(){ MyServlet myServlet = new MyServlet();​ return new ServletRegistrationBean(myServlet,"/my","/my02"); }​​ @Bean public FilterRegistrationBean myFilter(){​ MyFilter myFilter = new MyFilter();// return new FilterRegistrationBean(myFilter,myServlet()); FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter); // /*是原生servlet的写法                       ,/**是spring的写法 filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/css/*")); return filterRegistrationBean; }​ @Bean public ServletListenerRegistrationBean myListener(){ MySwervletContextListener mySwervletContextListener = new MySwervletContextListener(); return new ServletListenerRegistrationBean(mySwervletContextListener); }}

扩展:DispatchServlet 如何注册进来

容器中自动配置了 DispatcherServlet 属性绑定到 WebMvcProperties;对应的配置文件配置项是 spring.mvc                     。

通过 ServletRegistrationBean<DispatcherServlet> 把 DispatcherServlet 配置进来                    。

老师这里错了吧            ,dispatcherServlet是用@Bean标签注册到了容器中

这个注册类应该是将dispatcherservlet封装注册到tomcat服务器的Servletcontext全局作用域中

Servlet是要被ServletContext管理才能生效的      ,DispatcherServletRegistrationBean的作用就是把这个servlet交给ServletContext管理

默认映射的是 / 路径。

拦截器是在请求发过来的时候交给Spring去拦截的(dispatcherServlet

3            、定制化

编写自定义的配置类 xxxConfiguration;+ @Bean替换                     、增加容器中默认组件;视图解析器

最常用:Web应用 编写一个配置类实现 WebMvcConfigurer 即可定制化web功能;+ @Bean给容器中再扩展一些组件

@Configurationpublic class AdminWebConfig implements WebMvcConfigurer{} @EnableWebMvc

@ EnableWebMvc+ 实现 WebMvcConfigurer —— @Bean 可以全面接管SpringMVC                      ,所有规则全部自己重新配置; 实现定制和扩展功能

拦截器原理

拦截器(Interceptor)和过滤器(Filter)的执行顺序 过滤前-拦截前-Action处理-拦截后-过滤后

拦截器(Interceptor)使用 interceptor 的执行顺序大致为:

请求到达 DispatcherServlet DispatcherServlet 发送至 Interceptor                 ,执行 preHandle 请求达到 Controller 请求结束后   ,postHandle 执行

过滤器                     ,拦截器这种类似的都是责任链模式                 。

1           、根据当前请求                    ,找到HandlerExecutionChain【可以处理请求的handler以及handler的所有 拦截器(拦截器链)】

2        、先来顺序执行 所有拦截器的 preHandle方法

1                      、如果当前拦截器prehandle()返回为true                        。则执行下一个拦截器的preHandle()

2              、如果当前拦截器返回为false    。直接 倒序执行所有已经执行了的拦截器的 afterCompletion()方法;

3    、如果任何一个拦截器返回false             。直接跳出不执行目标方法

4                       、所有拦截器都返回True                        。执行目标方法

5                 、倒序执行所有拦截器的postHandle()方法        。

6、前面的步骤有任何异常都会直接倒序触发 afterCompletion

7                    、页面成功渲染完成以后,也会倒序触发 afterCompletion

preHandle顺序执行                 ,postHandle和afterCompletion都是逆序执行                        ,afterCompletion会在preHandle返回false/任何异常发生时/渲染视图完成后执行         。

图解拦截器原理:

1                     、实现HandlerInterceptor 接口 /** * 登录检查 * 1    、配置好拦截器要拦截哪些请求 * 2                、把这些配置放在容器中 */@Slf4jpublic class LoginInterceptor implements HandlerInterceptor {​ /** * 目标方法执行之前 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//@Slf4j提供的日志功能    ,检测出静态资源也被拦截 // String requestURI = request.getRequestURI(); // log.info("preHandle拦截的请求路径是{}",requestURI);​ //登录检查逻辑 HttpSession session = request.getSession();​ Object loginUser = session.getAttribute("loginUser");​ if(loginUser != null){ //放行 return true; }​ //拦截住                       。未登录            。跳转到登录页 //如果重定向             ,写保存在session域中                        ,前端要${session.msg},视频获取不到        ,因为login页中获取的是request里的msg,所以获取不到      。 //这里使用转发 request.setAttribute("msg","请先登录");// re.sendRedirect("/"); request.getRequestDispatcher("/").forward(request,response); return false; }​ /** * 目标方法执行完成以后 */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { log.info("postHandle执行{}",modelAndView); }​ /** * 页面渲染以后 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { log.info("afterCompletion执行异常{}",ex); }}

preHandle

用来拦截处理器的执行         ,preHandle方法将在Controller处理之前调用的                      。SpringMVC里可以同时存在多个interceptor                       ,它们基于链式方式调用            ,每个interceptor都根据其声明顺序依次执行                。这种链式结构可以中断      ,当方法返回false时整个请求就结束了   。

方法的返回值是布尔类型                      ,方法如果返回false                ,那后面的interceptor和Controller都不会执行(通常都会响应一个自定义的 Http 错误码给客户端)                     。如果返回值为true   ,则接着调用下一个interceptor的preHandle方法                    。如果当前是最后一个interceptor                     ,接下来就会直接调用Controller的处理方法。

postHandle:

postHandle 会在Controller方法调用之后                    ,但是在DispatcherServlet 渲染视图之前调用                 。因此我们可以在这个阶段,对将要返回给客户端的ModelAndView进行操作                        。

afterCompletion:

afterCompletion在当前interceptor的preHandle方法返回true时才执行    。该方法会在整个请求处理完成后被调用                 ,就是DispatcherServlet渲染视图完成以后                        ,主要是用来进行资源清理工作             。需要注意的是    ,afterCompletion在interceptor链式结构中以相反的顺序执行             ,也就是说先申明的interceptor返回会后调用                        。

2                     、配置拦截器

把这些配置放在容器中        。

/** * 1        、编写一个拦截器实现HandlerInterceptor接口 * 2            、拦截器注册到容器中(实现WebMvcConfigurer的addInterceptors) * 3                     、指定拦截规则【如果是拦截所有                        ,静态资源也会被拦截】 4           、/*只代表当前目录下        ,/**同时还包含了子文件夹(类路径又是什么意思 ) */@Configurationpublic class AdminWebConfig implements WebMvcConfigurer {​ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) .addPathPatterns("/**") //所有请求都被拦截包括静态资源 .excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**"); //放行的请求 }}

文件上传

1        、页面表单<!-- method="post" enctype="multipart/form-data" 文件上传表单的固定写法         。enctype就是encodetype就是编码类型的意思                       。multipart/form-data是指表单数据中由多部分构成既有文本数据         ,又有文件等二进制数据 --> <form method="post" action="/upload" enctype="multipart/form-data"> <input type="file" name="file"><br> <input type="submit" value="提交"></form> 2                      、文件上传代码 /** * MultipartFile 自动封装上传过来的文件 //各位记得设置上传最大空间值                       ,放的图片太大会有异常 */ @PostMapping("/upload") public String upload(@RequestParam("email") String email, @RequestParam("username") String username, //表单里面的文件项 @RequestPart("headerImg") MultipartFile headerImg, @RequestPart("photos") MultipartFile[] photos) throws IOException {​ log.info("上传的信息:email={}            ,username={}      ,headerImg={}                      ,photos={}", email,username,headerImg.getSize(),photos.length);​ if(!headerImg.isEmpty()){ //保存到文件服务器                ,OSS服务器 String originalFilename = headerImg.getOriginalFilename(); //名字不重复   ,加UUID就可以了,然后后面拼接上后缀名就可以了 headerImg.transferTo(new File("H:\\cache\\"+originalFilename)); }​ if(photos.length > 0){ for (MultipartFile photo : photos) { if(!photo.isEmpty()){ String originalFilename = photo.getOriginalFilename(); photo.transferTo(new File("H:\\cache\\"+originalFilename)); } } } return "main"; }​ 3              、文件上传自动配置类

在配置文件中可设置文件上传大小

//文件上传大小配置            。单个文件                     ,整个请求spring.servlet.multipart.max-file-size=10MBspring.servlet.multipart.max-request-size=100MB

异常

1    、默认规则

默认情况下                    ,Spring Boot提供/error处理所有错误的映射

对于机器客户端,它将生成JSON响应                 ,其中包含错误                        ,HTTP状态和异常消息的详细信息      。

对于浏览器客户端    ,响应一个“ whitelabel             ”错误视图             ,以HTML格式呈现相同的数据

要对其进行自定义                        ,添加View解析为error

替换调mvc组件error(也就是白页)

要完全替换默认行为        ,可以实现 ErrorController并注册该类型的Bean定义         ,或添加ErrorAttributes类型的组件以使用现有机制但替换其内容                      。

error/下的4xx                       ,5xx页面会被自动解析;

2                       、定制错误处理逻辑

1                 、自定义错误页

error/404.html error/5xx.html;有精确的错误状态码页面就匹配精确            ,没有就找 4xx.html;如果都没有就触发白页

2、@ControllerAdvice+@ExceptionHandler 处理全局异常;底层是 ExceptionHandlerExceptionResolver 支持的      ,因为标了@ExceptionHandler注解

/** * 处理整个web controller的异常 */@Slf4j@ControllerAdvicepublic class GlobalExceptionHandler { @ExceptionHandler({ArithmeticException.class,NullPointerException.class}) //处理哪些异常 算数异常                      ,空指针异常 public String handleArithException(Exception e){​ log.error("异常是:{}",e); return "login"; //视图地址 }}

3                    、@ResponseStatus+自定义异常 ;底层是 ResponseStatusExceptionResolver 解析器处理                ,因为标了@ResponseStatus注解   ,把responsestatus注解的信息                     ,底层调用 response.sendError(statusCode, resolvedReason);然后还是下面的流程                    ,没有解析器可以解析,然后tomcat发送的/error到mvc                 ,找4xx                        ,5xx页面

//设置状态码 和异常信息 程序执行到这里时主要将注解中的信息获得@ResponseStatus(value= HttpStatus.FORBIDDEN,reason = "用户数量太多")public class UserTooManyException extends RuntimeException {​ public UserTooManyException(){​ } public UserTooManyException(String message){ super(message); }}​

4                     、自定义实现 HandlerExceptionResolver 处理异常;把优先级调高(一旦出现异常优先被其处理)    ,可以作为默认的全局异常处理规则

@Order(value= Ordered.HIGHEST_PRECEDENCE) //优先级             ,数字越小优先级越高@Componentpublic class CustomerHandlerExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {​ try { response.sendError(511,"我喜欢的错误"); } catch (IOException e) { e.printStackTrace(); } return new ModelAndView(); }}​

ErrorViewResolver 实现自定义处理异常;

主动调用response.sendError()                 。error请求就会转给controller                        ,如果没有4叉叉这些页面        ,就会调用BeanNameViewResolver解析器         ,返回error白页(为mvc的错误页面                       ,组件View)

你的异常没有任何人能处理   。tomcat底层调用 response.sendError()                     。error请求就会转给controller            ,如果没有4叉叉这些页面      ,就会调用Tomcat自己的错误页面

以上都是由basicErrorController 控制器处理                      ,要去的页面地址是 ErrorViewResolver解析器解析 ;

@PathVariable(rest风格)    、@RequestHeader                、@RequestParam                     、@CookieValue        、@RequestBody            、@RequestAttribute(用来请求域中取数据                ,然后请求转发)                     、@ModelAttribute           、@MatrixVariable(矩阵变量)

整合mybatis

1        、纯配置模式

全局配置文件

SqlSessionFactory: 自动配置好了

SqlSession:自动配置了 SqlSessionTemplate 组合了SqlSession

@Import(AutoConfiguredMapperScannerRegistrar.class);

Mapper: 只要我们写的操作MyBatis的接口标注了 @Mapper 就会被自动扫描

可以修改配置文件中 mybatis 开始的所有配置;

# 第一种方式:纯配置模式# 配置mybatis规则 yml:-------------------------------------------mybatis:// config-location: classpath:mybatis/mybatis-config.xml #全局配置文件位置 mapper-locations: classpath:mybatis/mapper/*.xml #sql映射文件位置 configuration: map-underscore-to-camel-case: true 全局配置文件和在yml中使用configuration配置   ,二者只能选其一 推荐在yml中 可以不写全局配置文件                     ,所有全局配置文件的配置信息都放在configuration配置项中即可Mapper接口--->绑定Xml接口----------------------------------------------@Mapperpublic interface AccountMapper { public Account getAcct(Long id);}SQL实现的xml----------------------------------------------------<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.atguigu.admin.mapper.AccountMapper"><!-- public Account getAcct(Long id); --> <select id="getAcct" resultType="com.atguigu.admin.bean.Account"> select * from account_tbl where id=#{id} </select></mapper> mybatis使用规则:

导入mybatis官方starter

编写mapper接口                    。标注@Mapper注解

编写sql映射文件并绑定mapper接口

在application.yaml中指定Mapper配置文件的位置                    ,以及指定全局配置文件的信息 (建议不写全局配置文件,直接配置在mybatis.configuration

2                      、纯注解模式 //这个方式讲mybatis的时候就提了                 ,1.不适合复杂查询 2.写死了sql语句//主要是因为注解只适合小型的sql语句                        ,而公司里的语句都非常长    ,用xml配置会更清晰@Mapperpublic interface CityMapper {​ @Select("select * from city where id=#{id}") @Options(可实现xml中配置sql的其他功能             ,比如自增主键返回) public City getById(Long id);​ public void insert(City city);​} 3              、推荐混合模式 //一般都混合使用                        ,简单的sql语句就通过注解写在方法上@Mapperpublic interface CityMapper {​ @Select("select * from city where id=#{id}") public City getById(Long id);​ public void insert(City city);​}

最佳实战:

引入mybatis-starter依赖

配置application.yaml中        ,指定mapper-location位置即可

编写Mapper接口并标注@Mapper注解

简单方法直接注解方式

复杂方法编写mapper.xml进行绑定映射

在程序启动类上面标注@MapperScan("com.atguigu.admin.mapper") 简化         ,其他的接口就可以不用标注@Mapper注解。

整合 MyBatis-Plus

优点:数据层: mapper的CRUD不用写了

只需要我们的Mapper继承 BaseMapper 就可以拥有crud能力,因为BaseMapper声明了许多方法                 。如果不够用                       ,那就映射xml文件                        。

public interface UserMapper extends BaseMapper<User> {} 优点:业务层: Service 的CRUD也不用写了 /** * service的接口继承顶级service接口---IService */public interface UserService extends IService<User> {​}

service的实现类继承ServiceImpl----它是顶级接口IService的实现类            ,所以我们就可以直接用方法了    。

如果不够用      ,那就自己加在接口中UserService                      ,然后再来UserServiceImpl实现             。

@Servicepublic class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {} 3    、CRUD功能 //控制器方法 @GetMapping("/user/{id}") //restful风格: pn是请求参数                ,是url路径下?pn=1样子的值   , 而id是在路径变量中                     ,二者注意区分                        。给路径变量赋值(id=${user.id}) public String deleteUser(@PathVariable("id") Long id, @RequestParam(value = "pn",defaultValue = "1")Integer pn, RedirectAttributes ra){//​ userService.removeById(id); //重定向携带参数                    ,自动添加到重定向url后面 ra.addAttribute("pn",pn); return "redirect:/dynamic_table"; }​​ @GetMapping("/dynamic_table") public String dynamic_table(@RequestParam(value="pn",defaultValue = "1") Integer pn,Model model){ ​ //从数据库中查出user表中的用户进行展示 //构造分页参数 //第几页为pn,通过参数传进来                 ,每页显示多少条为2 Page<User> page = new Page<>(pn, 2); //调用page进行分页                        ,Wrapper为条件    ,没有条件就写null //userPage有很多有关分页的信息 Page<User> userPage = userService.page(page, null);​​ model.addAttribute("users",userPage);​ return "table/dynamic_table"; } //使用分页还需要的配置             ,分页拦截器@Configurationpublic class MyBatisConfig { /** * MybatisPlusInterceptor * 扫一眼源码                        ,这个貌似跟SpringBoot的拦截器还不一样        ,这个拦截器是发生在服务器和数据库之间的         ,不涉及路径拦截(可能说的不对) * @return */ @Bean public MybatisPlusInterceptor paginationInterceptor() { MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); // 设置请求的页面大于最大页后操作                       , true调回到首页            ,false 继续请求 默认false // paginationInterceptor.setOverflow(false); // 设置最大单页限制数量      ,默认 500 条                      ,-1 不受限制 // paginationInterceptor.setLimit(500); // 开启 count 的 join 优化,只针对部分 left join​ //这是分页拦截器 PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(); paginationInnerInterceptor.setOverflow(true); paginationInnerInterceptor.setMaxLimit(500L); mybatisPlusInterceptor.addInnerInterceptor(paginationInnerInterceptor);​ return mybatisPlusInterceptor; }}

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
win10升级win11预览版(win11预览版怎么升级正式版吗?Win11预览版直接升级到正式版本方法)