springBoot学习——spring+springMVC 集成mybatis 拦截器

news2025/1/13 11:58:19

目录

  • 引出
  • 入门案例:登陆和注册 & 用户信息分页 之 固定的步骤:
    • (1)建普通项目+配置pom.xml文件
    • (2)写主启动类 + application.yml文件
      • 【bug】pom.xml文件导了mybatis的包,但是application.yml文件没有配置
    • (3)static静态资源 + templates前端页面
    • (4)先用form表单尝试一下【有坑】关于日期传输和接收
    • (5)用vue发送axios请求【主流】@RequestBody接收
  • 集成mybatis:
    • 1. 配置文件application.xml文件,加入mybatis相关
    • 2. 注册功能的实现
      • (1)核心sql语句,获取新增数据的id:useGeneratedKeys="true" keyProperty="id"
      • (2)controll层代码
      • (3)工具类1:判断一个对象除了自增id外,其他不为null,如果字符串,且不为空
      • (3)工具类2:判断多个输入是否有空,支持Integer,String,Date类型
      • (4)前端页面:给后端发送json对象{"username":this.username,"password":this.password}
    • 3.登陆功能的实现
      • (1)controller层代码
      • (2)前端页面
    • 4.用户信息分页展示 路径变量传参"/list/{pageNum}/{pageSize}",@PathVariable("pageNum")
      • (1)controller层代码
      • (2)前端页面:[[${username}]]
  • 拦截器
    • 1.拦截谁addInterceptors,配置类(@Configuration + implements WebMvcConfigurer )中
    • 2.拦下来做什么—response.sendRedirect("/user/loginPage");,拦截器(@Component + implements HandlerInterceptor)
      • 【bug】302重定向,ERR_TOO_MANY_REDIRECTS,如果配置类中的,excludePathPatterns忘记加第一个反斜杠 /
  • 总结

引出


1.如何把mybatis也集成进spring中,有哪些步骤;
2.前端发送json对象,后端怎么接收;
3.前端传路径变量的rest风格,后端怎么接收处理;
4.spring的拦截的配置和使用;

在这里插入图片描述

入门案例:登陆和注册 & 用户信息分页 之 固定的步骤:

(1)建普通项目+配置pom.xml文件

<!--    继承一个父-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <version>2.3.0.RELEASE</version>
        <artifactId>spring-boot-starter-parent</artifactId>
    </parent>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

<!--    做web项目的包-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

<!--       前端模板引擎,功能类似于jsp-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

<!--        mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

<!--        分页工具,匹配springBoot的jar包-->
<!--        后面加spring-boot-starter,表示按照spring重新改写的版本-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.12</version>
        </dependency>

<!--        mybatis的包-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.1</version>
        </dependency>

<!--        druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.16</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        
<!--    工具包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.11</version>
        </dependency>

    </dependencies>

(2)写主启动类 + application.yml文件

主启动类

package com.tianju;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * springMVC的主启动类
 * 1.是主启动类;@SpringBootApplication
 * 2.启动:SpringApplication.run(Main.class);
 */
@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class);
    }
}

application.yml文件,注意如果有mybatis包,则必须配置一下,不然会报错

server:
  port: 80
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
    username: root
    password: 123

【bug】pom.xml文件导了mybatis的包,但是application.yml文件没有配置

项目启动失败,报错信息如下:

报错信息:

Failed to configure a DataSource: ‘url’ attribute is not specified and no embedded datasource could be configured.

Reason: Failed to determine a suitable driver class

在这里插入图片描述

(3)static静态资源 + templates前端页面

在这里插入图片描述

(4)先用form表单尝试一下【有坑】关于日期传输和接收

报错信息:

Failed to convert from type [java.lang.String] to type [java.util.Date] for value ‘2023-06-08’

在这里插入图片描述

解决方案:controller层接收参数上加注解

@DateTimeFormat(pattern = "yyyy-MM-dd") Date birthday

前端代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册</title>
</head>
<body>
注册
<form action="/user/register" method="post">
    用户名:<input type="text" name="username">
    密码:<input type="text" name="username">
    性别:
    <select name="sex">
        <option value="male"></option>
        <option value="female"></option>
    </select>
    生日:
    <input type="date" name="birthday">
    <input type="submit" value="提交">
</form>
</body>
</html>

在这里插入图片描述

实体类

package com.tianju.entity;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.text.Format;
import java.util.Date;

/**
 * user实体类
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private String username;
    private String password;
    private String sex;
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date birthday;

}

controller层代码

package com.tianju.controller;

import com.tianju.entity.ResData;
import com.tianju.entity.User;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Date;

/**
 * 用于处理用户相关请求的controller
 * 1.在容器中;@Controller
 * 2.访问路径;一级目录,@RequestMapping("/user")
 */

@Controller
@RequestMapping("/user")
public class UserController {
    // 首先到登陆页面,响应一个页面
    @RequestMapping("/registerPage")
    public String registerPage(){
        // 返回string类型
        return "/user/register";
    }

    // 在登陆页面,用户点击登陆按钮,处理请求
    @RequestMapping("register")
    @ResponseBody
    public ResData register(String username, String password, String sex,
                            @DateTimeFormat(pattern = "yyyy-MM-dd") Date birthday){
        System.out.println(birthday);
        User user = new User(username,password,sex,birthday);
        System.out.println(user);
        return new ResData(200, "ok", null);
    }
}

(5)用vue发送axios请求【主流】@RequestBody接收

要点:

  • 前端传参用Json对象传;
  • 后端接收需要加上@RequestBody注解;
  • 实体类中规定日期的格式, @JsonFormat(pattern = “yyyy-MM-dd”)

在这里插入图片描述

前端发送对象的方式:

(1) user对象逐个赋值,发送post请求

let user = {}
user.username = this.username;
user.password = this.password;
user.sex = this.sex;
user.birthday = this.birthday;
axios.post("/user/register",user)

(2) 直接创建好user对象,发送post请求

let user = {
    "username":this.username,
    "password":this.password,
    "sex":this.sex,
    "birthday":this.birthday,
}
axios.post("/user/register",user)

后端接收要加上@RequestBody,在类上加 @JsonFormat(pattern = “yyyy-MM-dd”)

    // 在登陆页面,用户点击登陆按钮,处理请求
    @RequestMapping("register")
    @ResponseBody
    // 如果前端用json对象发,后端需要加上@RequestBody
    public ResData register(@RequestBody User user){
        System.out.println(user);
        return new ResData(200, "ok", null);
    }

集成mybatis:

在这里插入图片描述
之前的模式下:
在这里插入图片描述
在spring中集成mybatis

在这里插入图片描述

1. 配置文件application.xml文件,加入mybatis相关

server:
  port: 80

# 1.连接数据库——对应之前 xml文件的数据库
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/javaweb?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
    username: root
    password: 123

# mybatis其他配置
mybatis:
  # 2.给实体类起别名,首字母小写
  type-aliases-package: com.tianju.entity
  configuration:
    # 3.开启驼峰命名
    map-underscore-to-camel-case: true
    # 4.让日志生效
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  # 5.扫描sql的位置
  mapper-locations: classpath:/mapper/*Mapper.xml

在这里插入图片描述

2. 注册功能的实现

(1)核心sql语句,获取新增数据的id:useGeneratedKeys=“true” keyProperty=“id”

<!--    TODO:如何知道新增的人的id-->
    <insert id="add" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO com_user(username,password,sex,birthday)
        VALUES (#{username},#{password},#{sex},#{birthday})
    </insert>

前端导包:

    <link rel="stylesheet" href="/bootstrap/css/bootstrap.css">
    <script src="/js/jquery-3.5.1.js"></script>
    <script src="/bootstrap/js/bootstrap.js"></script>
    <script src="/js/vue.min-v2.5.16.js"></script>
    <script src="/js/axios.min.js"></script>

(2)controll层代码

要点:

  • 前端用json对象发,后端需要加上@RequestBody User user;
  • 响应页面,不带数据,返回值为string
	@Autowired
    private IUserService userService;

    // 首先到注册页面,响应一个页面
    @RequestMapping("/registerPage")
    public String registerPage(){
        // 返回string类型
        return "/user/register";
    }

    // 在注册页面,用户点击注册按钮,处理请求
    @RequestMapping("register")
    @ResponseBody
    // 如果前端用json对象发,后端需要加上@RequestBody
    public ResData register(@RequestBody User user){
        System.out.println(user);
        System.out.println(EntityUtils.isAllNotNull(user));
        // 1.判断前端输入不为null或空,除了自增的id
        boolean allNotNull = EntityUtils.isAllNotNull(user);
        if (!allNotNull){
            System.out.println("输入有空");
            return new ResData(1001,"输入为空",null);
        }
        // 1.判断两个输入的密码是否一致
        if (!user.getPassword().equals(user.getRePassword())){
            return new ResData(1001,"两次密码不一致",null);
        }

        // 2.判断是否有重名的
        User userDB = userService.queryByUsername(user.getUsername());
        if (userDB!=null){
            System.out.println(userDB);
            return new ResData(1002,"用户名重复",null);
        }

        // 3.插入数据库中
        // 密码加密存储
        user.setPassword(SecureUtil.md5(user.getRePassword()));
        Integer addFlag = userService.add(user);
        System.out.println(user);
        if (addFlag<1){
            return new ResData(3001,"系统繁忙,请稍后",null);
        }
        return new ResData(200, "ok", null);
    }

(3)工具类1:判断一个对象除了自增id外,其他不为null,如果字符串,且不为空

EntityUtils.java文件

package com.tianju.util;

import java.lang.reflect.Field;

/**
 * 传入一个对象,判断对象里面的每个属性是否为null,或空;
 * 如果有null或空,返回false;否则,返回true;
 */
public class EntityUtils {
    public static boolean isAllNotNull(Object obj) {
        Class<?> aClass = obj.getClass();
        // 获取所有的files
        Field[] fields = aClass.getDeclaredFields();
        for(Field field:fields){
            // 如果第一个是id,id是数据库自增的,前端不输入,就跳过
            if (field.getName().contains("id")){
                continue;
            }
            field.setAccessible(true);
            Object value = null;
            try {
                value = field.get(obj);
            }
            catch (Exception e) {
                throw new RuntimeException(e);
            }

            if (value==null || "".equals(value)){
                return false;
            }
        }
        return true;
    }
}

(3)工具类2:判断多个输入是否有空,支持Integer,String,Date类型

StringUtils.java文件

package com.tianju.util;

import java.util.Date;

/**
 * 判读输入是否为空,支持可变长度参数
 */
public class StringUtils {
    /**
     * 最初始版本,只能判断string类型是否为null,空字符串
     */
    public static Boolean isBlank(String str){
        if(str==null || str.trim().equals("")){
            return true;
        }
        return false;
    }

    /**
     * 升级版本,
     * 可以判断String,Integer,Date类型
     * 是不是null,string判断是不是空
     * @param objs 可变长度参数
     * @return
     */
    public static  Boolean isBlank(Object... objs){
        for (Object obj:objs){
//            System.out.println(obj);
            if (obj==null){
                return true;
            }
            // 如果是字符串,判断是null,和 空字符串
            if (String.class.equals(obj.getClass())){
                String str = (String) obj;
                if(str==null || str.trim().equals("")){
                    return true;
                }
            // Integer 和 Date类型判断是不是null
            }else {
                if (obj==null){
                    return true;
                }
            }
        }
        return false;
    }

    public static void main(String[] args) {
        Object s = null;
        String str = (String) s;
//        System.out.println(str==null);
        Integer i = null;
        Boolean blank = isBlank(str,i,2);
        System.out.println(blank);
        System.out.println(isBlank("er",3,new Date()));
        System.out.println("UserId".contains("id"));
    }
}

(4)前端页面:给后端发送json对象{“username”:this.username,“password”:this.password}

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登陆</title>
    <link rel="stylesheet" href="/bootstrap/css/bootstrap.css">
    <script src="/js/jquery-3.5.1.js"></script>
    <script src="/bootstrap/js/bootstrap.js"></script>
    <script src="/js/vue.min-v2.5.16.js"></script>
    <script src="/js/axios.min.js"></script>
</head>
<body>
<div id="app">
    Vue登陆页面<br>
    用户名:<input type="text" v-model="username"><br>
    输入密码:<input type="text" v-model="password"><br>
    <button @click="loginBtn">提交</button>
</div>
<script>
    let app = new Vue({
        el:"#app",
        data:{
            username:"",
            password:"",
        },
        methods:{
            loginBtn(){
                axios.post("/user/login",{"username":this.username,"password":this.password})
                    .then(response=>{
                        let resp = response.data;
                        console.log(resp)
                        if (resp.code==200){
                            alert(resp.msg)
                            // 跳转到index页面,也要过controller
                            location.href = "/user/listPage"
                        }else {
                            alert(resp.msg)
                        }
                    })
            }
        },
        created(){
        }
    })
</script>

</body>
</html>

3.登陆功能的实现

(1)controller层代码

// 到登陆页面
    @RequestMapping("/loginPage")
    public String loginPage(){
        // 返回string类型
        return "/user/login";
    }

    // 处理用户输入的用户名和密码
    @RequestMapping("/login")
    @ResponseBody
    public ResData login(@RequestBody User user, HttpSession session){
        System.out.println(user);
        // 1.输入不为空
        if (StringUtils.isBlank(user.getUsername(),user.getPassword())){
            return new ResData(1001, "用户名|密码为空", null);
        }
        // 2.判断用户名,密码是否正确
        User userDB = userService.queryByUsername(user.getUsername());
        if (userDB==null || userDB.getPassword().equals(SecureUtil.md5(user.getPassword()))){
            return new ResData(1001, "用户名|密码错误", null);
        }
        // 3.登陆成功,保存到session
        session.setAttribute("user", userDB);
        return new ResData(200, "OK", null);
    }

(2)前端页面

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登陆</title>
    <link rel="stylesheet" href="/bootstrap/css/bootstrap.css">
    <script src="/js/jquery-3.5.1.js"></script>
    <script src="/bootstrap/js/bootstrap.js"></script>
    <script src="/js/vue.min-v2.5.16.js"></script>
    <script src="/js/axios.min.js"></script>
</head>
<body>
<div id="app">
    Vue登陆页面<br>
    用户名:<input type="text" v-model="username"><br>
    输入密码:<input type="text" v-model="password"><br>
    <button @click="loginBtn">提交</button>
</div>
<script>
    let app = new Vue({
        el:"#app",
        data:{
            username:"",
            password:"",
        },
        methods:{
            loginBtn(){
                axios.post("/user/login",{"username":this.username,"password":this.password})
                    .then(response=>{
                        let resp = response.data;
                        console.log(resp)
                        if (resp.code==200){
                            alert(resp.msg)
                            // 跳转到index页面,也要过controller
                            location.href = "/user/listPage"
                        }else {
                            alert(resp.msg)
                        }
                    })
            }
        },
        created(){
        }
    })
</script>

</body>
</html>

4.用户信息分页展示 路径变量传参"/list/{pageNum}/{pageSize}",@PathVariable(“pageNum”)

(1)controller层代码

要点:

  • 共享值用ModelAndView,前端获取 [[${username}]]
  • 路径变量传参"/list/{pageNum}/{pageSize}",@PathVariable(“pageNum”);
// 到list页面
    // 1.直接到页面
//    @RequestMapping("/listPage")
    public String listPage(){
        // 返回string类型
        return "/user/list";
    }
    // 2.共享值
    @RequestMapping("/listPage")
    public ModelAndView listPageMV(){
        ModelAndView mv = new ModelAndView("/user/list"); // 到哪个页面
        mv.addObject("username", "peter"); // 共享的值
        return mv;
    }

    // 处理list页面的请求,pageNum,pageSize
    @RequestMapping("/list/{pageNum}/{pageSize}")
    @ResponseBody
    public ResData userList(@PathVariable("pageNum") Integer pageNum,
                            // TODO:可以多个注解吗?答案:用路径变量必须都传,所以下面无效
//                            @RequestParam(value = "pageSize",defaultValue = "3")
                            @PathVariable("pageSize") Integer pageSize){
        PageInfo<User> pageInfo = userService.queryList(pageNum, pageSize);
        System.out.println(pageInfo);
        return new ResData(200, "OK", pageInfo);
    }

(2)前端页面:[[${username}]]

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>列表</title>
    <link rel="stylesheet" href="/bootstrap/css/bootstrap.css">
    <script src="/js/jquery-3.5.1.js"></script>
    <script src="/bootstrap/js/bootstrap.js"></script>
    <script src="/js/vue.min-v2.5.16.js"></script>
    <script src="/js/axios.min.js"></script>
</head>
<body>
<div id="app">
    列表页面[[${username}]]<br>
    <div>
<!--        进行搜索-->
        <input type="text" v-model="pageSize">
        <button @click="searchBtn">提交</button>
    </div>
<!--    pageNum,pageSize,name,date,-->
    <table class="table-condensed table-hover table-striped table-responsive table-cell table-row-cell table-view table-bordered">
        <tr>
            <th>id</th>
            <th>username</th>
            <th>gender</th>
            <th>birthday</th>
        </tr>

        <tr v-for="user in pageInfo.list">
            <td>{{user.id}}</td>
            <td>{{user.username}}</td>
            <td>{{user.sex}}</td>
            <td>{{user.birthday}}</td>
        </tr>
    </table>
    <div>
<!--        首页,尾页,上下页,跳转到-->
        <button v-show="!pageInfo.isFirstPage" @click="toFirstPage">首页</button>
        <button v-show="pageInfo.hasNextPage" @click="toNextPage">下页</button>
        <button v-show="pageInfo.hasPreviousPage" @click="toPreviousPage">上页</button>
        <button v-show="!pageInfo.isLastPage" @click="toLastPage">尾页</button>
    </div>

</div>

<script>
    let app = new Vue({
        el:"#app",
        data:{
            pageInfo:{},
            pageSize:3,
        },
        methods:{
            // 设置pageNum 和 pageSize
            queryList(pageNum,pageSize){
                axios.post("/user/list/"+pageNum+"/"+pageSize)
                    .then(response=>{
                        let resp = response.data;
                        console.log(resp)
                        this.pageInfo = resp.data;
                    })
            },
            searchBtn(){
                this.queryList(1,this.pageSize)
            },
            // 首页,尾页,下页,上页
            toFirstPage(){
                this.queryList(1,this.pageSize)
            },
            toNextPage(){
                this.queryList(this.pageInfo.pageNum+1,this.pageSize)
            },
            toPreviousPage(){
                this.queryList(this.pageInfo.pageNum-1,this.pageSize)
            },
            toLastPage(){
                this.queryList(this.pageInfo.pages,this.pageSize)
            },

        },
        created(){
            this.queryList(1,3);

        }
    })
</script>

</body>
</html>

拦截器

拦截器是基于增强方法做的
拦截谁,在配置类中配置;——对应SpringMvcConfig.java文件
拦下来做什么;——interceptor/LoginAuthInterceptor.java文件

1.拦截谁addInterceptors,配置类(@Configuration + implements WebMvcConfigurer )中

要点:

  • 在soring的容器中,@Configuration
  • 是spring的配置类 implements WebMvcConfigurer

在这里插入图片描述

package com.tianju.config;

import com.tianju.inteceptor.LoginAuthInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * spring的配置类
 * 1.在容器,@Configuration
 * 2.是spring的配置类,
 */
@Configuration
public class SpringMvcConfig implements WebMvcConfigurer {
    @Autowired
    LoginAuthInterceptor loginAuthInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginAuthInterceptor)
                .addPathPatterns("/**") // 拦截器 /** 表示子孙目录
                .excludePathPatterns(
                        "/user/loginPage","/user/login",
                        "/user/registerPage","/user/register",
                        "/js/**","/css/**","/bootstrap/**"
                ); // 在拦截的基础上,放行谁
    }
}

2.拦下来做什么—response.sendRedirect(“/user/loginPage”);,拦截器(@Component + implements HandlerInterceptor)

要点:

  • 在容器中,@Component
  • 是拦截器,implements HandlerInterceptor
  • 拦下来做什么,登陆了,放行,返回true;没有登陆,重定向去登陆页面,返回false;
package com.tianju.inteceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * 拦截器相关,拦下来做什么
 * 1.在容器中,@Component
 * 2.是拦截器,implements HandlerInterceptor
 */
@Component
public class LoginAuthInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 如果登陆了,就放行
        HttpSession session = request.getSession();
        Object user = session.getAttribute("user");
        if (user!=null){
            return true;
        }else {
            // 没有登陆,去登陆页面
            response.sendRedirect("/user/loginPage");
            return false;
        }
    }
}

【bug】302重定向,ERR_TOO_MANY_REDIRECTS,如果配置类中的,excludePathPatterns忘记加第一个反斜杠 /

报错:ERR_TOO_MANY_REDIRECTS

原因:.excludePathPatterns里面的路径反斜杠没加

在这里插入图片描述


总结

1.集成mybatis,在application.yml配置文件中进行配置;
2.前端传参用Json对象传,后端接收需要加上@RequestBody注解,实体类中规定日期的格式, @JsonFormat(pattern = “yyyy-MM-dd”);
3.获取新增数据的id:useGeneratedKeys=“true” keyProperty=“id”;
4.路径变量传参"/list/{pageNum}/{pageSize}“,后端接收用@PathVariable(“pageNum”);
5.后端共享值用ModelAndView,前端获取用[[${username}]];
6.spring配置类:在soring的容器中,@Configuration;是spring的配置类 implements WebMvcConfigurer;
7.拦截器(@Component + implements HandlerInterceptor),拦下来做什么—response.sendRedirect(”/user/loginPage");
8.拦截器在Spring配置中使用addInterceptors方法;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/679381.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Drag Your GAN论文解读,基于点的交互式操作拖动到生成图像[DragGAN]

只需要鼠标的点击就可以自动修图的产品&#xff0c;火爆问世&#xff0c;可以说是超越PS&#xff0c;神一般的存在了&#xff0c;而且没有门槛&#xff0c;对于普通大众来说直接可以上手使用&#xff0c;这个是PS完全不具备的。更关键的是&#xff0c;这款产品跟PS明显区别在于…

如何系统地自学 Python?

&#x1f482; 个人网站:【海拥】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 目录 前言为什么选择Python作…

【Intel 黑客松大赛】基于YOLO的杂草-农作物检测分类系统

目录 一、赛题简介&#xff1a;计算机视觉挑战——检测并清除杂草二、基于YOLO的杂草-农作物检测分类2.1、YOLO简介2.2、基于YOLO的杂草-农作物检测分类解决方案 三、基于YOLO的杂草-农作物检测分类系统设计3.1、基于flask框架的demo应用程序后端3.2、基于Vue框架的demo应用程序…

Qt6.2教程——4.QT常用控件QPushButton

一&#xff0c;QPushButton简介 QPushButton是Qt框架中的一种基本控件&#xff0c;它是用户界面中最常见和最常用的控件之一。QPushButton提供了一个可点击的按钮&#xff0c;用户可以通过点击按钮来触发特定的应用程序操作。比如&#xff0c;你可能会在一个对话框中看到"…

Unity编辑器扩展-第七集-应用键/显示提示词

第六集链接&#xff1a;Unity编辑器扩展-第六集-创建窗口/批量填图_菌菌巧乐兹的博客-CSDN博客 一、本节目标效果展示 1.我们有时候需要多次使用编辑窗口&#xff0c;但是每次一点执行&#xff0c;就关掉了&#xff0c;就很烦&#xff0c;所以我们希望&#xff0c;点击按钮&…

Spring Bean的实例化过程

一、前言 对于写Java的程序员来说&#xff0c;Spring已经成为了目前最流行的第三方开源框架之一&#xff0c;在我们充分享受Spring IOC容器带来的红利的同时&#xff0c;我们也应该考虑一下Spring这个大工厂是如何将一个个的Bean生产出来的&#xff0c;本期我们就一起来讨论一…

2023年6月GESP能力等级认证Python一级真题

2023-06 GESP等级考Python一级真题 题数&#xff1a;27 分数&#xff1a;100 测试时长&#xff1a;90min 一、单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09; 1. 以下不属于计算机输出设备的有&#xff08; A&#xff09;。&#xff08;2分&#xff09; A…

几个Arcpy代码应用案例

1 案例一 删除特定记录 使用 arcpy 从 ArcGIS 中的图层中删除特定记录。可以使用更新游标&#xff08;UpdateSursor&#xff09;和 SQL 查询来识别和删除所需的记录。以下是如何删除特定图层记录的示例 import arcpy selectedParcelsselectedParcels expres…

分子碰撞频率和自由程------从一个物理小问题解剖自己的数学思维

物理学12-8节中&#xff0c;关于分子平均碰撞的解说如下&#xff1a; &#xff08;一&#xff09;分子碰撞自由程公式 第一个公式中&#xff0c;lamda v / z中&#xff0c;v的单位是m/s, z的单位是A/s, 其中A是常数。那么lamda描述的结果是m/A, 这正是长度单位。 此公式lamda…

利用正弦定理证明两角和差公式

首先用正弦定理&#xff0c;证明sin(AB)sinAcosBcosAsinB。 另外&#xff0c;其它的两角和差公式&#xff0c;都可以用三角函数奇偶性、诱导公式等推导出来&#xff0c;无需再用正弦定理证明一遍。

耗时一个月!手撸博客系统,主打美观实用!

先附上博客链接RoCBlog 关于博客 关于博客 RoCBlog 完成耗时&#xff1a;20天 起初是想搭建自己的博客&#xff0c;看了网上许多开源框架&#xff0c;感觉没啥意思&#xff0c;于是决定自己写一套 纯手撸VueSpringboot 其实是个我一边学vue一边写出来的东西&#xff0c;前期…

团体程序设计天梯赛-练习集L1篇⑩

&#x1f680;欢迎来到本文&#x1f680; &#x1f349;个人简介&#xff1a;Hello大家好呀&#xff0c;我是陈童学&#xff0c;一个与你一样正在慢慢前行的普通人。 &#x1f3c0;个人主页&#xff1a;陈童学哦CSDN &#x1f4a1;所属专栏&#xff1a;PTA &#x1f381;希望各…

(贪心) 1221. 分割平衡字符串 ——【Leetcode每日一题】

❓ 1221. 分割平衡字符串 难度&#xff1a;简单 平衡字符串 中&#xff0c;L 和 R 字符的数量是相同的。 给你一个平衡字符串 s&#xff0c;请你将它分割成尽可能多的子字符串&#xff0c;并满足&#xff1a; 每个子字符串都是平衡字符串。 返回可以通过分割得到的平衡字符…

【JAVA反序列化】序列化与反序列化Java反射URLDNS链

文章目录 原生序列化与反序列化概述为什么需要序列化和反序列化&#xff1f;应用场景(涉及到将对象转换成二进制&#xff0c;序列化保证了能够成功读取到保存的对象)涉及的协议好处为什么会产生反序列化漏洞&#xff1f;可能反序列化的形式&#xff1f;代码演示 Java反射基础补…

Java try-catch块

Java的try块用于封装可能会抛出异常的代码。它必须在方法内部使用。 如果在try块中的特定语句处发生异常&#xff0c;后续的代码块将不会执行。因此&#xff0c;建议不要在try块中放置不会抛出异常的代码。 Java的try块必须后跟catch块或finally块。 Java try-catch语法 try…

JDBC ResultSet源码解读

通过Debug方式看下源码&#xff1a; 1.Debug程序&#xff0c;找到返回的 ResultSet 的引用 2. 查看ResultSet中的rowData 3. 查看 rows 我们可以看到rows是一个数组&#xff0c;里面存放了我们查询得到的数据&#xff08;我的表中一共7条数据&#xff09;。 4. 查看rows中的元…

【总结】网页状态码——200、302、304、400、404、405、500

200正常 500异常–服务器异常Java代码 细节&#xff1a;null和空&#xff0c;null调用方法会出现空指针异常 400异常----传参相关的异常 get方法长度限制 400异常&#xff0c;加了RequestParam(value “name”) 必须传值 400异常&#xff0c;后端类型是Integer&#xff0c…

c# 基于微信wechat_qrcode opencv插件,网络二维码图片批量识别(一)

一、基本概念 微信开源了其二维码的解码功能&#xff0c;并贡献给 OpenCV 社区。其开源的 wechat_qrcode 项目被收录到 OpenCV contrib 项目中。从 OpenCV 4.5.2 版本开始&#xff0c;就可以直接使用。 该项目 github 地址&#xff1a; https://github.com/opencv/opencv_contr…

中国电子学会2023年05月份青少年软件编程C++等级考试试卷二级真题(含答案)

一、编程题(共5题&#xff0c;共100分) 1. 数字放大 给定一个整数序列以及放大倍数x&#xff0c;将序列中每个整数放大x倍后输出。 时间限制&#xff1a;1000 内存限制&#xff1a;65536 【输入】 包含三行&#xff1a; 第一行为N&#xff0c;表示整数序列的长度(N ≤ 100)&a…

yandex地图js学习

由于百度地图在国外的某些寻路的场景不太完善&#xff0c;所以试用了一下俄罗斯的开源地图。同google地图一样&#xff0c;规划路线需要申请apikey&#xff0c;但无需绑定信用卡&#xff0c;每天的免费调用次数也非常够用。 yandex maps开发文档 申请apikey 只需要创建账号&…