Spring Boot

Spring Boot

SpringBoot概述

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

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

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

集成日志

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

统一异常处理

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

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

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

### 登录功能

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

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

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包

<!--JWT组件-->
<dependency>
	<groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    	        <version>4.4.0</version>
        </dependency>

​ 导入JWTUtil

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,账号

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

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

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.前端将查询的方法抽取出来,需要用的时候调用该方法即可.

<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转换)

@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语句进行添加:

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等),可以使用,但是日后会有地方要进行逻辑处理,所以不建议过多使用.

相关推荐

  1. SpringBoot

    2024-07-14 19:36:02       47 阅读
  2. springboot

    2024-07-14 19:36:02       34 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-14 19:36:02       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-14 19:36:02       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-14 19:36:02       58 阅读
  4. Python语言-面向对象

    2024-07-14 19:36:02       69 阅读

热门阅读

  1. pnpm 如何安装指定版本

    2024-07-14 19:36:02       26 阅读
  2. Feedback

    2024-07-14 19:36:02       17 阅读
  3. 数据库崩溃时事务的恢复机制

    2024-07-14 19:36:02       16 阅读
  4. 怎样获取openid?

    2024-07-14 19:36:02       16 阅读
  5. Android - 云游戏本地悬浮输入框实现

    2024-07-14 19:36:02       18 阅读