SpringBoot笔记3-thymeleaf/登录模块/拦截器/文件上传

thymeleaf初体验:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

使用模板引擎的步骤:

1.引入thymeleaf页面模板引擎:

        <!--thymeleaf-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

2.在每个页面都要引入thymeleaf命名空间,如下:

<html xmlns:th="http://www.thymeleaf.org">

在这里插入图片描述
链接的使用:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

代码演示:

第一步:导入spring-boot-start-thymeleaf的场景依赖;

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
 </dependency>

success页面准备:

注意命名空间的引入:

<html lang="en" xmlns:th="http://www.thymeleaf.org">
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title >Title</title>
</head>
<body>
<h1 th:text="${msg}">这是页面的默认值</h1><br>
<!--th:text="${msg}"从后台取值-->
</body>
</html>

controller接收请求:

package com.fan.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class ViewTestController {

    @RequestMapping("/toPage")
    public String toPage(Model model){
        System.out.println("测试thy");
        //model中的数据是放在请求域中request.setAttribute("a","abc");
        model.addAttribute("msg","你好,模板引擎,thymeleaf");
        return "success";
    }
}

然后页面发送请求进行测试:
http://localhost:8080/toPage
结果:
在这里插入图片描述

springboot整合thymeleaf页面:

spring-boot-configuration-processor包是一个让yml文件自定义的配置能提示的一个工具。

构建后台管理系统的模板(登录模块):

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

登录页的跳转:
在这里插入图片描述

检查登录页的css等静态资源的引用:

在这里插入图片描述

在这里插入图片描述

解决重复提交页面表单的处理:

在这里插入图片描述

在这里插入图片描述

两个方法:
在这里插入图片描述

在这里插入图片描述

controller代码演示:

package com.fan.controller;
import com.fan.pojo.LoginUser;
import com.fan.service.LoginUserService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;

@Controller
public class LoginController {
    @Resource
    private LoginUserService loginUserService;
    @GetMapping(value = {"/login","/"})
    public String tologin(){
        return "login";
    }

    //****核心是讲一个登录分成了两个,一个是重定向到主页,一个是接收重定向请求,转发到主页
    @PostMapping(value = "/login")
    public String login(LoginUser loginUser, HttpSession session, Model model, RedirectAttributes attributes){
        LoginUser loginUser1 = loginUserService.getLoginUserByNameAndPassword(loginUser);
        System.out.println("前端传一个user对象,从后台查出的loginUser:"+loginUser1);
        if(loginUser1 != null ){
            session.setAttribute("loginUser",loginUser1);
            model.addAttribute("msg","登录成功");
            //因为转发地址栏不会变,所以登录成功后,我们要让地址栏发生改变,这里选择重定向跳转页面
            return "redirect:/main.html";//发送一个main的get请求
        }else{
            model.addAttribute("msg","用户名或者密码错误");
            return "login";//要知道重定向是不能带model,所以这里用转发
        }
    }

    @GetMapping("/main.html")//类似于我们请求一个js,或者html页面资源
    public String mainPage(HttpSession session,Model model){
        //为了不让用户直接登录此页面,我们需要验证session
        Object loginUser = session.getAttribute("loginUser");
        if(loginUser != null){
            return "main";
        }else{
            //踢回到登录页
            model.addAttribute("msg","请重新登录");
            return "login";
        }

    }
}

在这里插入图片描述

测试:当我们直接访问main页面的时候:
在这里插入图片描述

替换右上角登录的用户名和头像:

我们原先的做法:在一个标签内写,然后后台取到的值会覆盖掉两个标签之间的内容。
在这里插入图片描述
现在我们需要一个行内写法:[[${}]]

在这里插入图片描述

代码演示:在页面找到显示当前登录用户的地方,然后将《a》和《a》之间的内容替换成以下行内写法:

 <a href="javascript:;">[[${session.loginUser.username}]]</a>

然后页面测试:

抽取thymleaf公共页面:

在我们的模板中,我们经常会希望包含其他模板中的部分,例如页脚,页眉,菜单等部分。

为了做到这一点,Thymeleaf需要我们定义这些要包含的部分“片段”,这可以使用该th:fragment属性来完成。

注意:抽取公共页面的时候也要构建一个完整的页面:包含html,head,body等。

以后遇到地址都可以使用thymeleaf的写法:@{/} /后写地址,这样以后我们写地址,可以给我们动态加上项目名。很方便,以后部署项目的时候,如果需要改变项目名,我们都不需要改变源代码;

假设我们创建了一个公共的页面common.html,包含每个页面的页眉,页脚,和导航栏等。

如下:

<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org">

  <body>
  
    <div th:fragment="footerside">
      &copy; 2011 The Good Thymes Virtual Grocery
    </div>
  
  </body>
  
</html>

上面的代码定义了一个片段footerside,我们可以使用th:insert或th:replace属性之一轻松地将其包含在主页中.如下(其中common 为公共页面的文件名):

<body>
  ...
  <div th:insert="common :: footerside}"></div> 
</body>

片段规范语法

th:insert和th:replace(和th:include)之间的差异:
和之间有什么区别th:insert和th:replace(和th:include,因为3.0不推荐)

th:insert 最简单:它将简单地将指定的片段作为其主机标签的主体插入(即把片段标签整个插入到引用处内部)。

th:replace实际上将其主机标签替换为指定的片段。

th:include与相似th:insert,但不插入片段,而是仅插入该片段的内容。

代码演示:

<footer th:fragment="copy">
  &copy; 2011 The Good Thymes Virtual Grocery
</footer>
<body>

  ...

  <div th:insert="footer :: copy"></div>

  <div th:replace="footer :: copy"></div>

  <div th:include="footer :: copy"></div>
  
</body>

将导致:

<body>
  <div>
    <footer>
      &copy; 2011 The Good Thymes Virtual Grocery
    </footer>
  </div>

  <footer>
    &copy; 2011 The Good Thymes Virtual Grocery
  </footer>

  <div>
    &copy; 2011 The Good Thymes Virtual Grocery
  </div>
  
</body>

注意:我们只抽取公共的js,css,其他不是公共的js保留在原页面。原页面的js等前面都带/,common页面js等带/,如@{/js/jquery-1.10.2.min.js}

错误总结:抽取公共页面是一个体力活,也是一个细心活,不用忘了th:等,当修改完错误后我们使用maven的插件中的clean清理一下缓存看效果。(遇到过这个坑)

common.html:

<div th:fragment="commonscript">
    <!-- Placed js at the end of the document so the pages load faster -->
    <script th:src="@{/js/jquery-1.10.2.min.js}"></script>
    <script th:src="@{/js/jquery-ui-1.9.2.custom.min.js}"></script>
    <script th:src="@{/js/jquery-migrate-1.2.1.min.js}"></script>
    <script th:src="@{/js/bootstrap.min.js}"></script>
    <script th:src="@{/js/modernizr.min.js}"></script>
    <script th:src="@{/js/jquery.nicescroll.js}"></script>

    <!--common scripts for all pages-->
    <script th:src="@{/js/scripts.js}"></script>
</div>

引用:

<div th:replace="common :: commonscript"></div>

在这里插入图片描述

js的引用可以直接这样:我们不需要和th:href一样,有两个href,一个是链接静态的,一个是链接动态的。

<div id="commonscript">
    <!-- Placed js at the end of the document so the pages load faster -->
    <script th:src="@{/js/jquery-1.10.2.min.js}"></script>
    <script th:src="@{/js/jquery-ui-1.9.2.custom.min.js}"></script>
    <script th:src="@{/js/jquery-migrate-1.2.1.min.js}"></script>
    <script th:src="@{/js/bootstrap.min.js}"></script>
    <script th:src="@{/js/modernizr.min.js}"></script>
    <script th:src="@{/js/jquery.nicescroll.js}"></script>

</div>

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

查看页面源代码:

在这里插入图片描述
修改公共页面的超链接等:

在这里插入图片描述

修改主页:

在这里插入图片描述

修改公共页面的用户名:找到dropdown下的管理员,并用行内元素的写法 [[${取出session中的值}]]

在这里插入图片描述

退出功能( session.invalidate()):

在这里插入图片描述


	@GetMapping({"/login","/"})
    public String toLogin(){
        return "login";
    }
    //注销
    @GetMapping("/logout")
    public String logout(HttpSession session){
       //清除session。invalidate:作废
        session.invalidate();

        return "redirect:/login";//让其重定向到登录页面
    }

表单遍历:

在这里插入图片描述
页面遍历取值:先在controller中向数据模型中存值:
model.addAttribute(“users”,users);

@GetMapping("/basic_table")
  public String basic_table(Model model){
      List<LoginUser> users = loginUserMapper.getLoginUsers();
      System.out.println(users);
      model.addAttribute("users",users);
      return "table/basic_table";
  }

然后页面遍历值:

   <tbody>
       <tr th:each="user,stat: ${users}">
           <td th:text="${stat.count}">3</td>
           <td th:text="${user.id}">Larry</td>
           <td th:text="${user.username}">the Bird</td>
           <td th:text="${user.password}">@twitter</td>
       </tr>
   </tbody>

添加状态:行号等
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

拦截器:

springboot中的拦截器使用:

第一步:编写拦截器,写一个拦截器的包interceptor,并编写登录的拦截器:
在这里插入图片描述
拦截器方法说明:
preHandle:在请求处理之前进行调用(Controller方法调用之前)
postHandle:请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
afterCompletion:在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)

拦截器类实现HandlerInterceptor 接口:

package com.fan.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();
        Object loginUser = session.getAttribute("loginUser");
        System.out.println("拦截器:"+loginUser);
        if(loginUser != null){
            return true;
        }
        //不符合条件的给出提示信息,并转发到登录页面

        request.setAttribute("msg","被拦截器拦截,请先登录");
        //转发到/个请求
        request.getRequestDispatcher("/").forward(request,response);
        return false;
    }

    @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 {

    }
}


 

2.将我们的拦截器放到容器中,并配置拦截规则:注意@Configuration要写到类上。

package com.fan.config;
import com.fan.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**")//要拦截的路径,我们这里拦截所有
                .excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**");//哪些不需要拦截的资源路径
    }
}


转发与重定向页面跳转的区别:

在进行web开发时,跳转是最常见的,今天在这里来学习下2种跳转:

第一种是request.getRequestDispatcher().forward(request,response):

1、属于转发,也是服务器跳转,相当于方法调用,在执行当前文件的过程中转向执行目标文件,两个文件(当前文件和目标文件)属于同一次请求,前后页共用一个request,可以通过此来传递一些数据或者session信息,request.setAttribute()和request.getAttribute()。

2、在前后两次执行后,地址栏不变,仍是当前文件的地址。

3、不能转向到本web应用之外的页面和网站,所以转向的速度要快。

4、URL中所包含的“/”表示应用程序(项目)的路径。

第二种是response.sendRedirect():

1、属于重定向,也是客户端跳转,相当于客户端向服务端发送请求之后,服务器返回一个响应,客户端接收到响应之后又向服务端发送一次请求,一共是2次请求,前后页不共用一个request,不能读取转向前通过request.setAttribute()设置的属性值。

2、在前后两次执行后,地址栏发生改变,是目标文件的地址。

3、可以转向到本web应用之外的页面和网站,所以转向的速度相对要慢。

4、URL种所包含的"/"表示根目录的路径。

特殊的应用:对数据进行修改、删除、添加操作的时候,应该用response.sendRedirect()。如果是采用了request.getRequestDispatcher().forward(request,response),那么操作前后的地址栏都不会发生改变,仍然是修改的控制器,如果此时再对当前页面刷新的话,就会重新发送一次请求对数据进行修改,这也就是有的人在刷新一次页面就增加一条数据的原因。

如何采用第二种方式传递数据:

1、可以选择session,但要在第二个文件中删除;

2、可以在请求的url中带上参数,如"add.htm?id=122"

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在类上使用@Slf4j打日志:

在这里插入图片描述

放行静态资源:

/css可以理解为static文件下的css文件夹,其他类似:
在这里插入图片描述

第二种方式:配置静态资源的访问路径:

在这里插入图片描述

在这里插入图片描述

推荐第一种,因为第二种方式每一个页面都要改静态资源的路径。

在这里插入图片描述

总结拦截器的使用:

在这里插入图片描述

看拦截器的执行顺序:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

然后登陆测试,再直接访问main页面测试;

代码演示;
编写自定义的拦截器LoginIntercepter :

package com.fan.admin.intercepter;

import com.fan.admin.entity.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Slf4j
@Configuration
public class LoginIntercepter implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler
                             ) throws Exception {
        String requestURI = request.getRequestURI();
        log.info("preHandle拦截器的请求路径是{}",requestURI);
        //登录检查的逻辑
        HttpSession session = request.getSession();
        LoginUser loginUser = (LoginUser) session.getAttribute("loginUser");
        if(loginUser != null){
            return true;
        }
        //拦截住未登录,跳转到登录页
        session.setAttribute("msg","请先登录");
        //使用转发来获取session中的值
        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);
    }
}

配置拦截器(将自定义的拦截器注册到容器中):

package com.fan.admin.config;

import com.fan.admin.intercepter.LoginIntercepter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

public class AdminWebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginIntercepter())
                .addPathPatterns("/**")
                .excludePathPatterns("/","login","/css/**",
                        "/fonts/**","/images/**","/js/**");
    }
}

拦截器的源码探究:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

如果当前拦截器返回false:
在这里插入图片描述

拦截器总结:

在这里插入图片描述

在这里插入图片描述

文件上传:

文件上传的使用:

在这里插入图片描述

修改文件上传表单页面:

在这里插入图片描述
form表单的请求和类型等:
在这里插入图片描述
代码:

 <form role="form" method="post" enctype="multipart/form-data" th:action="@{/upload}">
     <div class="form-group">
         <label for="exampleInputEmail1">邮箱</label>
         <input name="email" type="email" class="form-control" id="exampleInputEmail1" placeholder="请输入邮箱">
     </div>
     <div class="form-group">
         <label for="exampleInputPassword1">上传者</label>
         <input name="uploadusername" type="text" class="form-control" id="exampleInputPassword1" placeholder="请输入上传者名字">
     </div>
     <div class="form-group">
         <label for="exampleInputFile">头像</label>
         <input name="headerimg" type="file" enctype="multipart/form-data" id="exampleInputFile">
         <p class="help-block">单文件上传</p>
     </div>
     <div class="form-group">
         <label for="exampleInputFile2">生活照</label>
         <input name="photos" id="exampleInputFile2" type="file" enctype="multipart/form-data" multiple>
         <p class="help-block">多文件上传</p>
     </div>
     <div class="checkbox">
         <label>
             <input type="checkbox"> Check me out
         </label>
     </div>
     <button type="submit" class="btn btn-primary">上传</button>
 </form>

在这里插入图片描述

在这里插入图片描述
controller:

//文件上传
    @PostMapping("/upload")
    public String upload(
            @RequestParam("email") String email,
            @RequestParam("uploadusername") String uploadusername,
            @RequestParam("headerimg") MultipartFile headerimg,
            @RequestParam("photos") MultipartFile[] photos
            ) throws IOException {
        log.info("上传的信息:email={},uploadusername={},headerimg={},photos={}",
                email,uploadusername,headerimg,photos.length);
        //单文件上传
        if(!headerimg.isEmpty()){
            //保存到文件服务器
            String originalFilename = headerimg.getOriginalFilename();
            //注意a文件夹要存在的
            headerimg.transferTo(new File("g:\\a\\"+originalFilename));
        }
        //多文件上传
        if(photos.length>0){
            for (MultipartFile photo : photos) {
                if(!photo.isEmpty()){
                    String originalFilename = photo.getOriginalFilename();
                    //注意a文件夹要存在的
                    photo.transferTo(new File("g:\\a\\"+originalFilename));
                }
            }
        }
        return "index";
    }

在这里插入图片描述

在这里插入图片描述

文件上传的源码探究:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值