Spring Boot + vue-element 开发个人博客项目开发(八、调试、密码加密和Swagger接口文档)
作为一个后端开发人员或者是前端开发人员,总归要沟通和调试项目的,前端要接口数据,但不知道接口地址,总不能一个个把接口地址发给前端把,这不现实,后端对编写及维护接口文档耗费不少精力。Swagger的作用就是对接口进行管理,所以前端只需要这一份接口翁当就可以对项目进行管理。
一、插件安装
安装一个Mybatis的插件,方便我们快速从代码调到mapper层代码,或是从mapper层返回代码,
点击左上角 File -> Settings -> Plugins
搜索Free,点击安装完成之后点击OK,之后重启IDEA即可dian
安装完成之后,再打开mapper包里面的类,就会多出来一个绿色箭头,点击绿色箭头就能跳转到对应的mapper.xml语句中
二、调试
在这里说一个在开发中很重要的流程,就是debug调试程序 ,在我们写程序的过程中,难免会有很多的bug出现,并不是每个bug都能一眼看出来的,靠我们一行一行去读把逻辑理顺,那工作量也太大了,这时调试就显现出来优越感
1. debug启动程序
debug是需要启动程序的,但并不是平时的启动项目按钮,启动debug使用甲壳虫图标,如下图,打开项目,在项目的启动图标边上有个甲壳虫标志,就是debug
点击这个小虫子,等待项目启动
项目启动成功后,我们试一下添加的接口进行debug一下,
首先我们在接口的入口处打一个断点,在Controller层中的新增方法中打断点,断点打在新增的方法中,点一下出现红色的小圆点即可,
然后在ServiceImpl.java 实现类中也打一个断点,在新增方法的方法体中打断点
然后回到Postman, 点击填入数据,点击Send发送
返回控制台,可以看到我们传输的数据
目前id和创建时间都为空,是因为我们没有传值,但是我们要注意这些数据的走向
按F8或者点击图标,可以跳到ServiceImpl.java 实现类中去,会发现实现类中新增的方法中有我们所所传输的数据
再按F8或者点击图标,会发现id变成了4,说明数据插入成功了
此时没有报错,再往下走一步, 按F8或者点击图标,就会到了Controller层,流程走完了,返回结果
按F8或者点击图标,就跳到了这里
到这里就算是走完了流程,我们去数据库中看一下,发现确实新增了id为4 的数据
debug流程走完了
三、用户密码加密
我们现在的密码都是明文储存的,这都是非常不安全的,在正常的公司开发过程中,公司都会有自己的加密方式,我们这里做的只是一个博客demo,没有什么商业价值,所以我们的加密方式采用MD5加密,
在我们添加加密类的时候,我们先引入一个工具,以后开发过程中也会经常用到,
Hutool工具:Hutool是一个Java工具包,也只是一个工具包,它帮助我们简化每一行代码,减少每一个方法,让Java语言也可以“甜甜的”
官方文档:https://www.hutool.cn/docs/#/
在项目的pom.xml中引入依赖
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.16</version>
</dependency>
依赖添加完成之后,
我们在util包中新建一个MD5Util.java类,里面有一个MD5方法,参数是我们要传递的密码,还有一个main函数
package com.blog.personalblog.util;
import cn.hutool.core.util.StrUtil;
import java.security.MessageDigest;
public class MD5Util {
public static String MD5(String s) {
if (StrUtil.isEmpty(s) || StrUtil.isBlank(s)) {
return null;
}
char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
try {
byte[] btInput = s.getBytes();
MessageDigest mdInst = MessageDigest.getInstance("MD5");
mdInst.update(btInput);
byte[] md = mdInst.digest();
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
return null;
}
}
public static void main(String[] args) {
String str = "123789";
System.out.println(MD5(str));
}
}
加密的工具类和方法有了,我们要使用它,在数据一拿到的时候,就对密码进行加密,所以在Controller层进行判断和加密,在添加和修改时候进行加密存储,我们的页面不展示用户的密码
Controller层代码修改如下:
/**
* 添加用户
* @return
*/
@PostMapping("/create")
public JsonResult<Object> userCreate(@RequestBody @Valid User user ) {
/**
* createUser没有返回值,直接变量名.方法调用即可
*/
if (StrUtil.isEmpty(user.getPassWord())) {
return JsonResult.error("密码为空,请输入密码!")
}
//密码加密存储
user.setPassWord(MD5Util.MD5(user.getPassWord()));
userService.createUser(user);
return JsonResult.success();
}
/**
* 修改用户
* @return
*/
@PostMapping("/update")
public JsonResult<Object> userUpdate(@RequestBody @Valid User user) {
/**
* updateUser没有返回值,直接变量名.方法调用即可
*/
if (StrUtil.isEmpty(user.getPassWord())) {
return JsonResult.error("密码为空,请输入密码!");
}
//密码加密存储
user.setPassWord(MD5Util.MD5(user.getPassWord()));
userService.updateUser(user);
return JsonResult.success();
}
这里就进行了对密码的加密存储
再添加一个手机号格式验证工具,在Util包中新建一个PhoneUtil.java类
package com.blog.personblog.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PhoneUtil {
/**
* 验证手机号
* @param mobile
* @return
*/
public static boolean checkMobile(String mobile){
/**
* 大陆手机号码11位数,匹配格式:前三位固定格式+后8位任意数
* 此方法中前三位格式有:
* 13+任意数
* 15+除4的任意数
* 18+除1和4的任意数
* 17+除9的任意数
* 147
*/
String phone_regex = "^((13[0-9])|(14[1,2,3,5,7,8,9])|(15[0-9])|(166)|(191)|(17[0,1,2,3,5,6,7,8])|(18[0-9])|(19[8|9]))\\d{8}$";
if (mobile.length() != 11) {
return false;
} else {
Pattern p = Pattern.compile(phone_regex);
Matcher m = p.matcher(mobile);
boolean isPhone = m.matches();
if (!isPhone) {
return false;
}
return true;
}
}
}
然后在Controller层中的新增和修改功能中增加手机号格式是否正确的判断
/**
* 添加用户
* @return
*/
@PostMapping("/create")
public JsonResult<Object> userCreate(@RequestBody @Valid User user ) {
/**
* createUser没有返回值,直接变量名.方法调用即可
*/
if (StrUtil.isEmpty(user.getPassWord())) {
return JsonResult.error("密码为空,请输入密码!");
}
//密码加密存储
user.setPassWord(MD5Util.MD5(user.getPassWord()));
//判断手机号格式是否正确
if (!PhoneUtil.checkMobile(user.getPhone())) {
return JsonResult.error("输入手机号码格式有误!")
}
userService.createUser(user);
return JsonResult.success();
}
/**
* 修改用户
* @return
*/
@PostMapping("/update")
public JsonResult<Object> userUpdate(@RequestBody @Valid User user) {
/**
* updateUser没有返回值,直接变量名.方法调用即可
*/
if (StrUtil.isEmpty(user.getPassWord())) {
return JsonResult.error("密码为空,请输入密码!");
}
//密码加密存储
user.setPassWord(MD5Util.MD5(user.getPassWord()));
//判断手机号格式是否正确
if (!PhoneUtil.checkMobile(user.getPhone())) {
return JsonResult.error("输入的手机号码格式有误!");
}
userService.updateUser(user);
return JsonResult.success();
}
手机号的格式规定了格式要求和位数要求,否则会报错,
代码修改完成记得重启项目!
提示:由于添加了MD5Util,在代码添加完重启时记得把左上角改成启动项
在Postman测试一下两个功能
先测试密码加密功能,(前提是保证手机号码11位且格式正确)
返回成功的结果后,刷新数据库,显示刚添加的数据中密码一栏时已经被加密了的密码
在测试手机号码的格式问题,输入10位数的密码,点击Send发送,显示手机号码格式不正确,
三、接入Swagger接口文档
3.1 什么是Swagger
作为一个后端开发人员或者是前端开发人员,总归要沟通和调试项目的,前端要接口数据,但不知道接口地址,总不能一个个把接口地址发给前端把,这不现实,后端对编写及维护接口文档耗费不少精力。
Swagger的作用就是对接口进行管理,所以前端只需要这一份接口翁当就可以对项目进行管理
3.2 Swagger介绍
官网地址:API Documentation & Design Tools for Teams | Swagger
3.3 使用Swagger的好处
- 无依赖:UI适用于任何开发环境,无论是本地还是Web
- 人性化:允许最终开发人员轻松交互并尝试您的API公开的每一个操作,以便于使用
- 易于导航:使用分类整齐的文档快速查找和使用资源和断点
- 所有浏览器支持:通过适用于所有主要浏览器Swagger UI 迎合所有可能的场景
- 完全课定制的:样式并通过完整的源代码访问您想要的发送调整您的 Swagger UI
- 完整的 OAS 支持:可视化 Swagger 2.0 或 OAS 3.0 中定义的API
3.4 引入Swagger
在pom.xml中引入相关依赖
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
3.5 在项目中使用Swagger
准备工作结束了,所谓接口文档,就要在接口中使用,
3.6 接口归类
首先在Controller层加上注解@Api
@Api 是为了描述这个Controller是哪个模块的接口,加入是用户的接口类,那么这个类会有对用户的增删改查不同的方法。
@RestController
@Api(tags = "用户管理")
@RequestMapping("/user")
public class UserController {
@Autowired
UserService userService;
3.7 接口方法
大的分类标注好了,利用@Api进行大的分类标注
接下来是每个接口方法的标题,
我们在每个接口方法上加上一个@ApiOperation注解,描述这个接口方法的功能,是增删改查四个的哪一个。
UserController.java完整代码
package com.blog.personblog.controller;
import cn.hutool.core.util.StrUtil;
import com.blog.personblog.entity.User;
import com.blog.personblog.service.UserService;
import com.blog.personblog.util.JsonResult;
import com.blog.personblog.util.MD5Util;
import com.blog.personblog.util.PhoneUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
@RestController
@Api(tags = "用户管理")
@RequestMapping("/user")
public class UserController {
@Autowired
UserService userService;
/**
* 用户列表
* @return
*/
@ApiOperation(value = "用户列表")
@PostMapping("/list")
public JsonResult<Object> list() {
/**
* findALL有返回值,需要对应的变量来接收
*/
List<User> userList = userService.findAll();
return JsonResult.success(userList);
}
/**
* 添加用户
* @return
*/
@ApiOperation(value = "添加用户")
@PostMapping("/create")
public JsonResult<Object> userCreate(@RequestBody @Valid User user ) {
/**
* createUser没有返回值,直接变量名.方法调用即可
*/
if (StrUtil.isEmpty(user.getPassWord())) {
return JsonResult.error("密码为空,请输入密码!");
}
//密码加密存储
user.setPassWord(MD5Util.MD5(user.getPassWord()));
//判断手机号格式是否正确
if (!PhoneUtil.checkMobile(user.getPhone())) {
return JsonResult.error("输入手机号码格式有误!");
}
userService.createUser(user);
return JsonResult.success();
}
/**
* 修改用户
* @return
*/
@ApiOperation(value = "修改用户")
@PostMapping("/update")
public JsonResult<Object> userUpdate(@RequestBody @Valid User user) {
/**
* updateUser没有返回值,直接变量名.方法调用即可
*/
if (StrUtil.isEmpty(user.getPassWord())) {
return JsonResult.error("密码为空,请输入密码!");
}
//密码加密存储
user.setPassWord(MD5Util.MD5(user.getPassWord()));
//判断手机号格式是否正确
if (!PhoneUtil.checkMobile(user.getPhone())) {
return JsonResult.error("输入的手机号码格式有误!");
}
userService.updateUser(user);
return JsonResult.success();
}
/**
* 删除用户
* @return
*/
@ApiOperation(value = "删除用户")
@PostMapping("/delete/{id}")
public JsonResult<Object> userDelete(@PathVariable(value = "id") int id) {
userService.deleteUser(id);
return JsonResult.success();
}
}
这就可以了,启动项目
我们的项目地址是localhost:8081/blog,
访问接口文档的地址是:localhost:8081/blog +Swagger路径
即接口文档地址为:http://localhost:8081/blog/swagger-ui/index.html
打开,出现以下界面:
3.8 报错及解决方案
问题:
进行了上面的配置,重启项目,
再访问http://localhost:8081/blog/swagger-ui/index.html
可能会直接显示拒绝访问:
查看控制台,发现项目没有启动起来:
通过everything查找blogLog日志文件查看一下打印的日志:发现报错如下,显示空指针
解决办法:
在启动项直接加一个注解:@EnableWebMvc即可
添加完成之后重启项目,控制台没有报错了
所以以后碰到有报错,可以先看控制台,然后去看相关的日志打印,看日志中具体报什么错误
四、配置Swagger
以上的步骤使得Swagger可用,但为了项目的规范,我们还需要对页面进行改造,版本,指定的Controller包等操作
我们在config配置包中新建一个Swagger3Config.java配置类
package com.blog.personblog.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
@Configuration
@EnableOpenApi
public class Swagger3Config {
@Bean
public Docket docket(){
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo()).enable(true)
.select()
//添加swagger接口提取范围,修改成指向你的controller包
.apis(RequestHandlerSelectors.basePackage("com.blog.personblog.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.title("个人博客系统接口文档")
.description("个人博客系统")
.version("1.0")
.build();
}
}
配置完,重启项目,还是打开原来的地址:http://localhost:8081/blog/swagger-ui/index.html
接口文档中出现了我们的配置信息,
前端只需要拿着这个接口文档就可以进行开发了,
但这个接口文档在项目上线的时候要去掉,保证系统的信息安全。
写完之后记得提交代码到Gitee
更多推荐
所有评论(0)