[ SpringBoot ]
一. 概述
1.为什么使用SpringBoot
Spring虽然有很多优点, 但是Spring框架的搭建非常麻烦
1. 配置麻烦,而且很多都是模版化的配置(固定的)
2. 需要添加很多依赖, 例如web层依赖jackson组件,需要我们自己添加, 版本也可能不匹配
基于以上两点,spring官方推出了SpringBoot .
2. 搭建
new project ---- java ----Maven
添加父工程 (不放在dependencies里面)
<!--依赖的父级工程-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
<relativePath/>
</parent>
添加依赖
<!--添加基本的 springweb 依赖-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
添加打包插件(不放在dependencies里面)
<!--打包插件-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.6.6</version>
</plugin>
</plugins>
</build>
添加启动类
package com.ffyc.news;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;/*springboot应用的启动类*/@SpringBootApplication
//@EnableScheduling
@MapperScan("com.ffyc.news.dao")
public class NewsApplication {public static void main(String[] args) {SpringApplication.run(NewsApplication.class);}
}
创建web层 service层 dao层 model层 config层(配置层) interceptor层(拦截器)
在resources下创建applicantion.yml文件(配置值的文件)
3. 配置值文件
application.properties
属性文件格式,内容为键值对 server.port=8080
properties 格式比较简单,没有什么难度,在此我们以第二种 yaml 格式为例.
application.yml(重要)
yml 是 YAML(YAML Ain’t Markup Language)语言的文件,以数据为中心.
1.yaml 基本语法: 语法结构:key:空格 value; ( 注意: 空格不能省略)
2. 以空格的缩进来控制层级关系,只要是左边对齐的一列数据都是同一个层级的;
3. 字面量直接写在后面就可以,字符串默认不用加上双引号或者单引号;
4. 以#作为注释符号.
5. 使用@Value 注解标签将配置文件中的内容映射到类中的属性. @Value("${user.name}")
4. Spring数据访问管理
数据源配置
为了连接数据库需要引入 jdbc 支持,在 pom.xml 中添加依赖 (记得添加 mysql 驱动依赖)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
在 application.yml 中配置数据源信息(本次使用的是阿里数据源)
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
#url: jdbc:mysql://127.0.0.1:3306/newsdb?serverTimezone=Asia/Shanghai
url: jdbc:mysql://192.168.244.128:3306/newsdb?serverTimezone=Asia/Shanghai
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource #指定数据库连接管理类
initialSize: 5
maxActive: 20
添加阿里数据源依赖
<!-- 阿里数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
复制一个前端项目, 删除里面不需要的文件和配置
5. 解决跨域问题
出现此错误需要解决跨域问题
添加配置类
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//配置类,启动时被扫描
public class CorsConfig {@Bean//等价于<bean id="" class=""/>配置我们的类(创建 配置 和返回对象),交给spring管理public CorsFilter corsFilter() {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);}}
虽然springboot简化了spring应用的搭建,将一些常用的基础组件自动配置
但是项目中会用到各种各样的组件,有的组件springboot没有提供自动配置,
需要我们自己来配置
springboot不使用xml文件配置,而是使用Java代码中配置
6.token拦截器
操作: 登录成功后在后端生成token, 在前端浏览器保存token
在util包下导入jwt(秘钥获得token),并添加依赖.
package com.ffyc.news.util;import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import com.ffyc.news.model.Admin;
import com.ffyc.news.model.User;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);//秘钥及加密算法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()).withClaim("type",admin.getType())//在token里面显示管理员类型.withExpiresAt(expireDate)//设置有效时间.sign(algorithm);//第三部分}catch (Exception e){e.printStackTrace();return null;}return token;}public static String getUserToken(User user) {String token = "";try {//过期时间 为1970.1.1 0:0:0 至 过期时间 当前的毫秒值 + 有效时间Date expireDate = new Date(new Date().getTime() + 3600*24*14*1000);//秘钥及加密算法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",user.getId()).withClaim("email",user.getEmail()).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);}public static Admin getOperAdmin(String token){DecodedJWT decodedJWT = JWTUtil.getTokenInfo(token);int adminid = decodedJWT.getClaim("id").asInt();Admin admin = new Admin();admin.setId(adminid);return admin;}}
<!--jwt组件-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.2</version>
</dependency>
操作: 在后端创建token验证拦截器,并配置拦截器
添加拦截器
package com.ffyc.news.interceptor;import com.auth0.jwt.JWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ffyc.news.model.Result;
import com.ffyc.news.util.JWTUtil;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;//拦截器
public class TokenInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token =request.getHeader("token");System.out.println("token 认证拦截器:"+token);if(JWTUtil.verify(token)){//认证tokenreturn true;//离开拦截器,继续向后到达自定义处理器}else {response.setContentType("text/html;charset=utf-8");//设置响应内容的格式Result result = new Result(401,"token认证失败",null);response.getWriter().write(new ObjectMapper().writeValueAsString(result));return false;//不继续向后执行}}
}
配置拦截器
package com.ffyc.news.config;import com.ffyc.news.interceptor.TokenInterceptor;
import com.ffyc.news.interceptor.UserTokenInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;@Configuration
public class WebConfig implements WebMvcConfigurer{//添加(配置)拦截器public void addInterceptors(InterceptorRegistry registry) {//添加(配置)管理员拦截器InterceptorRegistration inter = registry.addInterceptor(new TokenInterceptor());//注册自己的拦截器inter.addPathPatterns("/api/**"); //进入拦截器的地址 (管理员需要拦截的地址)inter.excludePathPatterns("/api/loginCtl/login");//不进入拦截器的地址//添加(配置)用户拦截器InterceptorRegistration userInter = registry.addInterceptor(new UserTokenInterceptor());//注册自己的拦截器userInter.addPathPatterns("/user/userCtl/**"); //进入拦截器的地址 (管理员需要拦截的地址)//以下不需要进入拦截器userInter.excludePathPatterns("/user/userCtl/createCode");//生成邮箱验证码不进入拦截器的地址userInter.excludePathPatterns("/user/userCtl/saveUser");//注册保存不进入拦截器的地址userInter.excludePathPatterns("/user/userCtl/create");//生成图形验证码不进入拦截器的地址userInter.excludePathPatterns("/user/userCtl/login");//用户登录不进入拦截器的地址}}
7. 管理员管理
数据初始化: 建一张admin表,并填充几个数据
查询基本的管理员列表
为列表添加查询条件功能
前端( 注意: 添加在el-card下面就好了 )
<!-- 查询条件--><el-row :gutter="20"><el-col :span="6"><el-input placeholder="账号" v-model="form.account"></el-input></el-col><el-col :span="6"><el-input placeholder="电话" v-model="form.phone"></el-input></el-col><el-col :span="6"><el-button type="primary" icon="el-icon-search" @click="findList()" >查询</el-button></el-col></el-row>
后端:大部分和基础查询的写法一致,少部分有改变 例如:
将数据封装在admin对象里面,同时添加判断
<resultMap id="adminMap" type="Admin"><id column="id" property="id"></id><result column="account" property="account"></result><result column="gender" property="gender"></result><result column="phone" property="phone"></result><result column="type" property="type"></result><result column="oper_time" property="operTime"></result><!--封装操作人对象数据--><association property="admin" javaType="Admin"><result column="oper_account" property="account"></result></association></resultMap><select id="admins" parameterType="Admin" resultMap="adminMap">selecta.id,a.account,a.gender,a.phone,a.type,oa.account oper_account,a.oper_timefromadmin ainner join admin oaon a.adminid = oa.idwhere a.type = 1<if test="account!=''">and a.account=#{account}</if><if test="phone!=''">and a.phone=#{phone}</if></select>
8. 分页组件
1. 后端使用mybatis分页组件, 快捷实现后端分页功能
添加分页组件依赖
<!-- pagehelper依赖 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
</dependency>
applicantion.yml中
spring:main:allow-circular-references: true #开始支持spring循环依赖
public PageInfo<Admin> admins(Admin admin){//告诉分页组件,当前页数,页数大小,会自动算出开始位置,并且会在sql后面自动添加limit语句PageHelper.startPage(admin.getPageNo(), admin.getPageSize());ArrayList<Admin> admins = adminDao.admins(admin);//会再生成一条sql 查询总条数 会把与分页相关的数据封装到PageInfo中PageInfo<Admin> pageInfo = new PageInfo<>(admins);return pageInfo;}
2. 前端使用elementui
<!-- 分页组件-->
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="form.pageNo"
:page-sizes="[2,4,6,8]"
:page-size="form.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
9. 新增管理员对话框
导入导入--注册组件--使用组件
添加方法,打开对话框(this.$refs.add.dialogVisible =true;)----调用方法
修改之前的div内容(例如this. form)
10.动态显示菜单数据
(1)搭建静态菜单信息
顺序: controller层---service层---dao层---mapper层
注意: menu是以ArrayList数组的形式返回
简单的数据直接以注解的形式在dao层查询, 不用到mapper层
(2)动态查询菜单信息
组件格式可以通过elementUI查找 (这里只展示部分代码)
11.新增并保存管理员
(1)后端接收
注意: token需要添加注解 @RequestHeader("token")
1.为管理员生成默认密码并加密密码
2.从token中获取当前管理员id
3.保存管理员信息到数据库的admin表,并拿到管理员id
4.保存给管理员分配的权限数据
12. 删除管理员
注意: 先删除关系表, 再删除管理员
13.修改管理员
14.添加登录时密码加密
修改登录
修改jwt密码加密