Spring Boot

Spring Boot

SpringBoot概述

​ 以Spring为基础进行开发的框架,对spring的搭建进行了简化,基于约定大于配置的思想,部分配置从配置转变为java类的编写,内嵌tomcat服务器可以快速创建一个企业级应用程序,有大量的核心功能:起步依赖和自动配置(主要还是配置繁琐和依赖多进行优化)

​ 起步依赖:spring基本的依赖会自动导入

​ 自动配置:spring启动时,通过配置的相关依赖自动加载配置

集成日志

​ 日志更新 昨天七月六号的日志文件被打包为:log.log.2024-07-06.0.gz的文件

统一异常处理

​ AOP的使用场景:集成日志,异常处理

​ 不修改原来代码的同时提供新功能,分离业务和非业务代码,使代码清晰简洁

搭建前端项目,实现前后端交互

复制代码
### 登录功能

​ 1.复制之前宿舍管理系统的前端项目 命名为newsweb

​ 2.前端发送异步请求,出现跨域问题

java 复制代码
package com.ffyc.news.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.Collections;

/*
    @Configuration添加在类上,表明此类是一个配置类 SpringBoot启动时,就会扫描该类
*/
@Configuration
public class CorsConfig {

    /*
        @Bean用在方法上,等同于<bean id="" class="">
            表示此方法会由程序员创建使用的类的对象,
            最终返回, 返回是交给spring框架统一管理的
    */

    //配置跨域处理的过滤器
    @Bean
    public CorsFilter corsFilter() {
        System.out.println("跨域过滤器");
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        //1,允许任何来源
        corsConfiguration.setAllowedOriginPatterns(Collections.singletonList("*"));
        //2,允许任何请求头
        corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);
        //3,允许任何方法
        corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);
        //4,允许凭证
        corsConfiguration.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(source);
    }
}

​ 3.在后端登陆成功后,生成token

​ 导入jwt jar包

xml 复制代码
<!--JWT组件-->
<dependency>
	<groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    	        <version>4.4.0</version>
        </dependency>

​ 导入JWTUtil

java 复制代码
package com.ffyc.news.Util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.ffyc.news.model.Admin;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JWT工具类
 */
public class JWTUtil {

    /**
     * 根据用户id,账号生成token
     * @param admin
     * @return
     */
    public static String getToken(Admin admin) {
        String token = "";
        try {
            //过期时间 为1970.1.1 0:0:0 至 过期时间  当前的毫秒值 + 有效时间
            Date expireDate = new Date(new Date().getTime() + 3600*1000*3);
            //秘钥及加密算法
            Algorithm algorithm = Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE");
            //设置头部信息
            Map<String,Object> header = new HashMap<>();
            header.put("typ","JWT");
            header.put("alg","HS256");
            //携带id,账号信息,生成签名
            token = JWT.create()
                    .withHeader(header)//第一部分
                    .withClaim("id",admin.getId())//第二部分
                    .withClaim("account",admin.getAccount())//第二部分
                    .withExpiresAt(expireDate)//第二部分
                    .sign(algorithm);//标签  加盐
        }catch (Exception e){
            e.printStackTrace();
            return  null;
        }
        return token;
    }

    /**
     * 验证token是否有效
     * @param token
     * @return
     */
    public static boolean verify(String token){
        try {
            //验签
            Algorithm algorithm = Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE");
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception e) {//当传过来的token如果有问题,抛出异常
            return false;
        }
    }

    /**
     * 获得token 中playload部分数据,按需使用
     * @param token
     * @return
     */
    public static DecodedJWT getTokenInfo(String token){
        return JWT.require(Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE")).build().verify(token);
    }

}

​ 4.前端保存用户token,账号

vue 复制代码
sessionStorage.setItem("adminToken",resp.data.result.adminToken); //会话期间存储,关闭浏览器后,数据就会销毁
sessionStorage.setItem("account",resp.data.result.account)

​ 5.在后端搭建管理员token验证的拦截器

java 复制代码
package com.ffyc.news.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ffyc.news.Util.JWTUtil;
import com.ffyc.news.model.Result;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.io.Reader;

@Component
public class AdminTokenInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("进入到拦截器");
        String adminToken = request.getHeader("adminToken");
        if(JWTUtil.verify(adminToken)){
            return true;
        }else {
            response.setContentType("text/html;charset=utf-8");
            PrintWriter writer = response.getWriter();
            Result result = new Result(401,"token验证失败",null);
            ObjectMapper objectMapper = new ObjectMapper();
            String json = objectMapper.writeValueAsString(result);
            writer.write(json);
            return false;
        }
    }
}

​ 6.测试拦截器

权限管理

业务分析

​ 回顾宿舍管理系统,一个管理员登陆到系统当中并没有什么权限限制,什么操作都可以做.

​ 稍微大一点的项目,都不是一个管理员操作的,可以有多个管理员参与,不同的管理员部门岗位不同,登陆后操作菜单也应该不一样,需要对不同的管理员分配对应的权限菜单

复制代码
##### 管理员管理

​ 由超级管理员(only 1)登录到系统中,然后添加其他普通管理员,并为其分配操作菜单

登录

​ 登录菜单需要动态显示,不同的管理员登录时可以根据给其分配的权限菜单动态显示

数据库设计
表单设计
  1. 管理员表 admin

    ​ id,account,password,phone,gender,type(1-超级管理员, 2-普通管理员),adminid,oper_time

  2. 菜单表 menu

    ​ id,name,url,type(1-系统菜单,2-普通菜单 系统菜单是不能分配给普通管理员的)

  3. 管理员_菜单表 admin_menu

    ​ id adminid menuid

数据库初始化数据:
  1. 超级管理员
  2. 菜单表中的菜单数据
编码
查询管理员列表

​ 查id,account,phone,gender,type,adminid,oper_time 只查询普通管理员(where type = 2)

为列表添加查询条件

1.为什么要添加查询条件

​ 方便我们快速的查询到想要的数据

​ 添加查询条件:

1.前端将查询的方法抽取出来,需要用的时候调用该方法即可.

html 复制代码
<script>
	export default {
		data() {
			return {
				tableData: [],
				form:{
					account:"",
					gender:"",
                    /* 这里注意向后传参不是null,而是空串 */
				}
			}
		},
		methods: {
			//查询按钮
			search(){
				this.admins();
			},
			admins(){
				this.$http.post("/adminCtl/adminList",this.form).then((resp) => {
                    	/* ↑ 这里注意,不能使用get请求传递参数,get请求传递参数的方法是?接数据,这里使用了请求体,需要用post方法进行传参
                        */
						this.tableData = resp.data.data;
				});
			}
		},
		mounted() {
			/* 向后端发送请求查询管理员列表 */
			this.admins();
		}
	}
</script>

2.后端使用Admin对象接收前端传过来的数据(@RequestBody进行json转换)

java 复制代码
@RequestMapping(path = "/adminList")
    public Result login(@RequestBody Admin admin){
        			/*   @RequestBody 对Json字符串进行转换 */
        List<Admin> list = adminService.findAdminList(admin);
        if(list!=null){
            return new Result(200,"登陆成功",list);
        }else {
            return new Result(201,"账号或密码错误",null);
        }
    }

3.Mapper中对sql语句进行添加:

sql 复制代码
WHERE a.type = 2
        <if test=" account!='' ">
	                     /* ↑ 不能为null,而是一个空串 */
            and a.account = #{account}
        </if>
        <if test=" gender!='' ">
            and a.gender = #{gender}
        </if>

注意这里的查询条件不能为null,form传回来的数据不是null而是一个空串

为列表添加分页功能

1.为什么要添加分页功能,它能实现什么效果

​ 为了限制一次查询过多的数据,提高查询效率

2.分析分页技术实现和条件

​ 必备条件:

​ 1.总记录数---总共有多少条数据(已知条件)

​ 2.每页显示的条数(已知条件)

​ 3.总页数 = 总记录数/每页显示的条数(不能整除 + 1)

​ 5%2==0?5:5/2+1

​ 4.分页实现---mysql使用的limit

​ LIMIT 0,2(第几个开始查询, 查询多少条)

​ 5.当前页码 n limit (n-1)*每页显示的条数

​ 前端向后端传递的数据:

​ 每页显示的条数

​ 当前页数

​ 后端向前端传递的数据:

​ 总记录数

​ 对应页的数据集合

​ 通过page组件来实现该功能

复制代码
<!-- pagehelper依赖 -->
<dependency>
	<groupId>com.github.pagehelper</groupId>
	<artifactId>pagehelper-spring-boot-starter</artifactId>
	<version>1.2.5</version>
</dependency>

application.yml文件配置	
spring:
  main: 
    allow-circular-references: true #开始支持spring循环依赖
  
  
service类中
// pageNum当前页面  pageSize每页大小
    public PageInfo<Admin> admins(Admin admin) {
        PageHelper.startPage(admin.getPageNo(), admin.getPageSize()); //1.会自动算出limit后面的开始位置
        List<Admin> admins =  adminDao.admins(admin);                //2.重新发一条sql,查询总条数
        PageInfo<Admin> pageInfo = new PageInfo<>(admins);
        return  pageInfo;
    }

pageInfo.getList();
pageInfo.getTotal()
PS:

​ 权限还可以分配到按钮级别,控制哪些按钮是否显示

补充:

注解

@SpringBootApplication

​ 使SpringBoot中的核心注解标签,用来启动

@ComponentScan

​ 声明要扫描该类

@Configuration

​ 加入@Configuration 注解,表明这就是一个配置类.有一个 myBean()的方法并用@Bean 进行注释,返回一个MyBean()的实例,表明这个方法是需要被Spring进行管理的bean @Bean 如果不指定名称的话,默认使用 myBean名称,也就是小写的名称.

@Bean

​ 相当于XML中的,放在方法的上面,而不类,意思是产生一个bean,并交给spring管理.

Lombok

​ 能干什么,有什么作用,解决什么问题

​ 简化大部分模板化复杂的代码(普通的Get Set等),可以使用,但是日后会有地方要进行逻辑处理,所以不建议过多使用.

相关推荐
Q_Q5110082857 分钟前
python的婚纱影楼管理系统
开发语言·spring boot·python·django·flask·node.js·php
长风破浪会有时呀19 分钟前
记一次接口优化历程 CountDownLatch
java
EyeDropLyq37 分钟前
线上事故处理记录
后端·架构
云朵大王44 分钟前
SQL 视图与事务知识点详解及练习题
java·大数据·数据库
我爱Jack1 小时前
深入解析 LinkedList
java·开发语言
一线大码2 小时前
Gradle 高级篇之构建多模块项目的方法
spring boot·gradle·intellij idea
27669582922 小时前
tiktok 弹幕 逆向分析
java·python·tiktok·tiktok弹幕·tiktok弹幕逆向分析·a-bogus·x-gnarly
用户40315986396633 小时前
多窗口事件分发系统
java·算法
用户40315986396633 小时前
ARP 缓存与报文转发模拟
java·算法
小林ixn3 小时前
大一新手小白跟黑马学习的第一个图形化项目:拼图小游戏(java)
java