创建springboot+Vue项目 1、创建springboot项目
2、准备数据表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 -- 创建数据库 create database big_event; -- 使用数据库 use big_event; -- 用户表 create table user ( id int unsigned primary key auto_increment comment 'ID', username varchar(20) not null unique comment '用户名', password varchar(32) comment '密码', nickname varchar(10) default '' comment '昵称', email varchar(128) default '' comment '邮箱', user_pic varchar(128) default '' comment '头像', create_time datetime not null comment '创建时间', update_time datetime not null comment '修改时间' ) comment '用户表'; -- 分类表 create table category( id int unsigned primary key auto_increment comment 'ID', category_name varchar(32) not null comment '分类名称', category_alias varchar(32) not null comment '分类别名', create_user int unsigned not null comment '创建人ID', create_time datetime not null comment '创建时间', update_time datetime not null comment '修改时间', constraint fk_category_user foreign key (create_user) references user(id) -- 外键约束 ); -- 文章表 create table article( id int unsigned primary key auto_increment comment 'ID', title varchar(30) not null comment '文章标题', content varchar(10000) not null comment '文章内容', cover_img varchar(128) not null comment '文章封面', state varchar(3) default '草稿' comment '文章状态: 只能是[已发布] 或者 [草稿]', category_id int unsigned comment '文章分类ID', create_user int unsigned not null comment '创建人ID', create_time datetime not null comment '创建时间', update_time datetime not null comment '修改时间', constraint fk_article_category foreign key (category_id) references category(id),-- 外键约束 constraint fk_article_user foreign key (create_user) references user(id) -- 外键约束 )
3、创建Springboot工程,引入对应的依赖(web、mybatis、mysql驱动)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <parent > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > 3.1.3</version > </parent > <groupId > org.jjq</groupId > <artifactId > big-event</artifactId > <version > 1.0-SNAPSHOT</version > <packaging > jar</packaging > <name > big-event</name > <url > http://maven.apache.org</url > <properties > <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding > </properties > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.mybatis.spring.boot</groupId > <artifactId > mybatis-spring-boot-starter</artifactId > <version > 3.0.0</version > </dependency > <dependency > <groupId > com.mysql</groupId > <artifactId > mysql-connector-j</artifactId > <version > 8.0.33</version > </dependency > </dependencies > </project >
4、配置文件application.yml中引入mybatis的配置信息
1 2 3 4 5 6 7 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/big_event username: root password: jinjiaqi123
5、创建包结构并准备实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Article { private Integer id; private String title; private String content; private String coverImg; private String state; private Integer categoryId; private Integer createUser; private LocalDateTime createTime; private LocalDateTime updateTime; }
1 2 3 4 5 6 7 8 9 10 public class Category { private Integer id; private String categoryName; private String categoryAlias; private Integer createUser; private LocalDateTime createTime; private LocalDateTime updateTime; }
1 2 3 4 5 6 7 8 9 10 11 public class User { private Integer id; private String username; private String password; private String nickname; private String email; private String userPic; private LocalDateTime createTime; private LocalDateTime updateTime; }
开发流程 1明确需求 2阅读接口文档 3思路分析 4开发 5测试
用户相关
6、编写Result实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package org.jjq.pojo;import lombok.AllArgsConstructor;import lombok.NoArgsConstructor;@NoArgsConstructor @AllArgsConstructor public class Result <T> { private Integer code; private String message; private T data; public static <E> Result<E> success (E data) { return new Result <>(0 , "操作成功" , data); } public static Result success () { return new Result (0 , "操作成功" , null ); } public static Result error (String message) { return new Result (1 , message, null ); } }
7、编写Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package org.jjq.controller;import org.jjq.pojo.Result;import org.jjq.pojo.User;import org.jjq.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @RequestMapping("/register") public Result register (String username,String password) { User u = userService.findByUserName(username); if (u==null ){ userService.register(username,password); return Result.success(); } else { return Result.error("用户名已被占用" ); } } }
8编写UserService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package org.jjq.mapper;import org.apache.ibatis.annotations.Insert;import org.apache.ibatis.annotations.Mapper;import org.apache.ibatis.annotations.Select;import org.jjq.pojo.User;@Mapper public interface UserMapper { @Select("select * from user where username=#{username}") User findByUserName (String username) ; @Insert("insert into user(username,password,create_time,update_time)"+ "values(#{username},#{password},now(),now())") void add (String username, String password) ; }
9编写Service实现层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package org.jjq.service.Impl;import org.jjq.mapper.UserMapper;import org.jjq.pojo.User;import org.jjq.service.UserService;import org.jjq.utils.Md5Util;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;@Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public User findByUserName (String username) { User u = userMapper.findByUserName(username); return u; } @Override public void register (String username, String password) { String md5String = Md5Util.getMD5String(password); userMapper.add(username,md5String); } }
10编写UserMapper
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package org.jjq.mapper;import org.apache.ibatis.annotations.Insert;import org.apache.ibatis.annotations.Mapper;import org.apache.ibatis.annotations.Select;import org.jjq.pojo.User;@Mapper public interface UserMapper { @Select("select * from user where username=#{username}") User findByUserName (String username) ; @Insert("insert into user(username,password,create_time,update_time)"+ "values(#{username},#{password},now(),now())") void add (String username, String password) ; }
11运行SpringBoot并在postman中进行测试
测试成功数据库中出现测试的数据就表示用户查询和注册功能已经完成了
12参数校验
传统方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @RequestMapping("/register") public Result register (String username,String password) { if (username!=null &&username.length()>=5 &&username.length()<=16 && password!=null &&password.length()>=5 &&password.length()<=16 ) { User u = userService.findByUserName(username); if (u==null ){ userService.register(username,password); return Result.success(); } else { return Result.error("用户名已被占用" ); } } else { return Result.error("参数不合法" ); } }
Spring Validation
Spring提供的一个参数校验框架,使用预定义的注解完成参数校验
1、引入Spring Validation依赖
1 2 3 4 5 6 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-validation</artifactId > </dependency >
2、在参数前面添加@Pattern注解
1 2 3 4 5 6 public Result register (@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$") String password) {}
3、在Controller类上添加@Validation注解
1 2 3 4 5 6 @Validated @RestController @RequestMapping("/user") public class UserController {}
参数校验失败异常处理
1 2 3 4 5 6 7 8 9 10 11 @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public Result handleException (Exception e) { e.printStackTrace(); return Result.error(StringUtils.hasLength(e.getMessage())? e.getMessage():"操作失败" ); } }
登录 2.1、登录功能 编写Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @RequestMapping("/login") public Result<String> login (@Pattern(regexp = "^\\S{5,16}$") String username,@Pattern(regexp = "^\\S{5,16}$") String password) { User loginUser = userService.findByUserName(username); if (loginUser==null ){ return Result.error("用户名错误" ); } if (Md5Util.getMD5String(password).equals(loginUser.getPassword())){ return Result.success("JWT token令牌" ); } return Result.error("密码错误" ); }
编写异常处理器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package org.jjq.exception;import org.jjq.pojo.Result;import org.springframework.util.StringUtils;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.RestControllerAdvice;@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public Result handleException (Exception e) { e.printStackTrace(); return Result.error(StringUtils.hasLength(e.getMessage())? e.getMessage():"操作失败" ); } }
在postman中测试
1 2 3 4 5 { "code": 0, "message": "操作成功", "data": "JWT token令牌" }
2.2、登录认证 令牌: 令牌就是一段字符串
承载业务数据,减少后续请求查询数据库的次数
防篡改,保证信息的合法性和有效性
JWT:
简介·:
全称:JSON Web Token(https://jwt.io/ )
定义了一种简介的、自包含的格式,用于通信双方以json数据格式安全的传输信息
组成
第一部分:Header(头),记录令牌类型、签名算法等。例如:{“alg”:HS256,“type”:“JWT”}
第二部分:Payload(有效载荷),携带一些自定义信息,默认信息等。例如:{“id”:1,“username”:“Tom”}
第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来
JWT-生成:
在Maven中引入JWT
1 2 3 4 5 6 7 8 9 10 11 12 <dependency > <groupId > com.auth0</groupId > <artifactId > java-jwt</artifactId > <version > 4.4.0</version > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > </dependency >
注意事项:
JWT校验时使用的签名秘钥,必须和生成JWT令牌时使用的秘钥是配套的
如果JWT令牌解析校验时报错,则说明JWT令牌被篡改或失效了,令牌非法
导入工具类JwtUtil
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package org.jjq.utils;import com.auth0.jwt.JWT;import com.auth0.jwt.algorithms.Algorithm;import java.util.Date;import java.util.Map;public class JwtUtil { private static final String KEY = "iloveyou" ; public static String genToken (Map<String, Object> claims) { return JWT.create() .withClaim("claims" , claims) .withExpiresAt(new Date (System.currentTimeMillis() + 1000 * 60 * 60 * 12 )) .sign(Algorithm.HMAC256(KEY)); } public static Map<String, Object> parseToken (String token) { return JWT.require(Algorithm.HMAC256(KEY)) .build() .verify(token) .getClaim("claims" ) .asMap(); } }
在Controller文件夹下创建ArticleController
1 2 3 4 5 6 7 8 9 10 11 @RestController @RequestMapping("/article") public class ArticleController { @GetMapping("/list") public Result<String> list () { return Result.success("所有文章的数据" ); } }
创建拦截器LoginInterceptor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Component public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("Authorization" ); try { Map<String, Object> claims = JwtUtil.parseToken(token); return true ; }catch (Exception e){ response.setStatus(401 ); return false ; } } }
创建config文件夹并且创建WebConfig类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private LoginInterceptor loginInterceptor; @Override public void addInterceptors (InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/login" ,"/user/register" ); } }
测试:
在postman的请求中添加Authorization将用户登录生成的token输到postman的Authorization中
取消Authorization后显示401状态码
——————————————————————-分割———————————————————————-
学习总结
端口号和虚拟目录
配置文件 第二种更好
配置信息的书写
打包插件