基于spring boot,spring mvc,配置,日志,spring ioc 和di, mybatis-plus,统一功能处理的博客系统。
目录
🍁页面展示
刚开始访问http:127.0.0.1:8080/blog_login.html是这样子的。

正确输入完用户名和密码就可以进入大厅页面
可以看到,这个页面把每篇博客都显示出来了,有每篇博客的标题,时间,正文,左边版块有登录用户的个人信息。查看全文,主页,写博客,注销等小按钮。
然后我们点击查看全文按钮

进来之后,很明显,这个正文显示了全部,而大厅页面的那个显示的是部分正文,这里为啥会显示编辑和删除呢,因为我们校验了登录用户和这篇文章的作者是同一个人,也就是是登录用户本人的文章。反之不是同一个人,就不显示编辑和删除。
假如我们点击删除

它弹出一个小框框,提示我们要不要删除。
如果点击编辑按钮,

里面就可以写文章了,写完之后点击更新文章,就将数据写入数据库了,然后页面会自动跳转大厅博客列表显示页面了。
这个博客系统小项目大体页面逻辑就是这样的,有登录页面,大厅博客列表显示页面,查看博客详情页面,编辑博客页面,以及个人信息小板块,删除小按钮,主页小按钮,写博客小按钮,注销小按钮。
🍁建表

创建一个叫user_info的用户表,先不说别的,里面肯定必须有delete_flag,create_time,update_time三个字段,然后也得有个主键id吧,其次就是用户名和密码,github地址.一共7个字段,,非常的通俗易懂。
然后看下博客表,记录每篇播客的相关信息。

也是有铁打不动的delete_flag,create_time,update_time以及主键id字段,其次就是得要有博客的标题,正文字段,最后这篇博客是谁写的,所以user_id关联用户表的主键id来表示这篇博客的作者。一共7个字段。
字段类型以及约束这里我没提,算了我只拿这个博客表来说啊,id为主键,就要保证它的非空和唯一性,所以加上not null和auto_increment约束,title和content的not null约束不必多说。字段类型我就不说了,看不懂大家去查去。其实也没啥可讲的这里,就到这里吧。
🍁创建项目

定好项目名字,选maven,点击next,

然后勾选Lombok和Spring Web和MySQL Driver依赖,因为我们用的是mybatis-plus,创建项目成功之后,得在xml依赖文件里手动添加对应得mybatis-plus依赖,里面就集成了mysql framework依赖,也就是mybatis-plus可以用,mybatis也可以用!
🍁添加mybatis-plus依赖
java
<!-- 添加mybatis-plus依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot4-starter</artifactId>
<version>3.5.15</version>
</dependency>
🍁配置yml文件
java
spring:
application:
name: spring-blog-demo #项目名
datasource:
url: jdbc:mysql://127.0.0.1:3306/java_blog_spring?
characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 配置打印MyBatis日志
map-underscore-to-camel-case: true #驼峰自动转化
mapper-locations: classpath:/mapper/**.xml #告诉mybatis我们的xml文件路径在哪
logging:
file:
name: logger/springboot.log #配置打印日志的存放地方
🍁MyBatisX插件创建部分项目结构

先得启用这个插件,然后操作按照下面这个顺序来

点完mysql之后,他会弹出一个下面的这个框

填好mysql数据库的账号和密码,然后Database就是你要连接的mysql里的哪个数据库名,点完ok之后,就可以显示你连接的具体数据库里的相关信息了。



点击MybatisX-Generator之后,会弹出下面这个东东

然后

最后点击Finish,就成功的自动生成service层和mapper层的相关代码了。
生成的效果如下,红框框的东东都是插件自动生成的。

其中mapper包----mybatis-plus的相关使用
service包----service层的,这里分了,接口和实现类。
然后resource底下的mapper包----也支持mybatis基础的xml写法,看你需要使用。
然后这也只是插件生成的部分东东,大部分需要我们自己写,只不过操作数据库相关的插件已经帮我们写好了绝大一部分。
🍁总体项目结构


然后我们启动下spring项目

启动成功,我们就把一些相关的配置搞好了,可以开始上手写业务代码了。
哦,忘了,在写业务代码之前,我们得把项目所要用到的公共模块给写好一部分。
🍁项目公共模块
🍀统⼀返回结果实体类
先给大家看看postman的数据响应结果

我们这里约定,后端统一返回的结果都得是code----data----errMsg这三个东东,code就是状态码的意思,这不是http响应状态码的意思,这个是我们通过代码处理了相关问题,是因为我们不想让后端给前端返回一个400什么的,前端他就只知道报了400错误码,他不知道具体原因,不方便前端进行处理,所以,我们可以设code为200表示成功啥的。。这个后面再讲。
data就不用多说了,返回前端所需要的数据。
errMsg就是有的时候前端给我们传的参数不合法,就是无法进行逻辑处理,这时候,data我们就不写,再设个业务处理失败的code状态码,errMsg就需要告诉前端出问题了。
我们先在enums包底下,创建一个枚举类,
java
@AllArgsConstructor
public enum ResultCodeEnum {
SUCCESS(200),
FAIL(-2),
UNLOGIN(-1),
;
@Getter
private int code;
}
枚举类的构造方法我们就不自己手动写了,直接加个@AllArgsConstructor全参的构造方法。
然后get方法我们也不写了,加个@Getter注解即可。
然后我们统一返回的都是code--data--errMsg这样的格式,所以我们完全可以创建个对象来这样表示,在pojo包底下写,而code--data--errMsg这样的格式,我们用Result类来表示,而又是响应,所以如下

Result类
java
@Data
public class Result<T> {
private int code;//业务码,不是http状态码
private String errMsg;
private T data;
public static <T> Result<T> ok(T data){
Result result=new Result();
result.setCode(ResultCodeEnum.SUCCESS.getCode());
result.setData(data);
return result;
}
public static <T> Result<T> fail(String errMsg){
Result result=new Result();
result.setCode(ResultCodeEnum.FAIL.getCode());
result.setErrMsg(errMsg);
return result;
}
public static <T> Result<T> unlogin(){
Result result=new Result();
result.setCode(ResultCodeEnum.UNLOGIN.getCode());
result.setErrMsg("用户未登录");
return result;
}
}
🍀统⼀返回结果
这个就是对于不同的返回结果进行处理,把它处理成code--data--errMsg这样的格式给前端。
所以自然要在advice统一结果返回包底下写。
ResponseAdvice类实现ResponseBodyAdvice接口不用多少

好像这个没啥可讲的,要是真不懂,可以去看我写的SpringBoot统一功能处理那篇博客里的统一数据返回格式那块。
🍀定义项目异常
在exception包底下

java
@Getter
public class BlogException extends RuntimeException {
private Integer code;
private String message;
public BlogException(String message) {
this.code = ResultCodeEnum.FAIL.getCode();
this.message = message;
}
public BlogException(Integer code, String message) {
this.code = code;
this.message = message;
}
}
继承RuntimeException不用多说,这是每个自定义异常类都需要继承的东东,这里重点讲下为啥要加@Getter注解,
由于我们在这个异常的构造方法里没加super(message),所以当下面这个逻辑执行

getmssage每错,我们已经没加没加super(message)了,如果再不加@Getter注解,那就getter不到message这个东东了,get不到,那就打印不到,就会报异常,虽然我有捕获Exception异常兜底,但这明显事与愿违了,大忌啊,我们既然写了这个代码,就要负责,做个专一的man。
🍀统一异常处理
这个统一异常处理返回结果是接近最后的返回数据格式,其返回结果不走统一返回结果那边,因为它加了@RestControllerAdvice===@ControllerAdvice+@ResponseBody,

这个@ControllerAdvice不用多说,统一返回结果也是用的这个注解,那为啥统一返回结果那里不加@ResponseBody注解,而这个统一异常处理要加呢?
我也搞不懂其实,但是站在我们使用者的视角下,可以这样理解,统一异常处理比较特殊,如果不加@ResponseBody注解,默认返回的就是视图。
java
@Slf4j
@RestControllerAdvice
public class ExceptionAdvice {
@ExceptionHandler(exception = Exception.class)
public Result handlerException(Exception e){
log.error("发生异常,e{}",e.getMessage());
return Result.fail(e.getMessage());
}
@ExceptionHandler
public Result handlerBlogException(BlogException e){
log.error("发生异常,e{}",e.getMessage());
return Result.fail(e.getMessage());
}
/*
校验参数,也就是传递的不是json对象,可以用这个
*/
@ResponseStatus(code= HttpStatus.BAD_REQUEST)
@ExceptionHandler(exception = {MethodArgumentNotValidException.class,HandlerMethodValidationException.class})
public Result handler(Exception e){
log.error("发生异常,e{}",e.getMessage());
return Result.fail("参数校验失败");
}
}
🍀与表相对的实体类
用户实体类

@TableName注解与数据库表名相匹配,加了@TableId注解----也就是不使用mybatis-plus给我们生成id雪花算法的值,而是使用数据库的id主键的AUTO_INCREMENT。
博客实体类也类似,不多讲了。

基本上我们的部分前置的东东都写好了,也就是可以开始写业务代码了。
🍁实现博客列表

我们来想想,前端传啥,后端传啥,登录完后,跳转到博客页面,也就是前端没传值,后端需要返回数据,那后端返回啥呢,首先肯定是code--data--errMsg这样的统一返回格式。data里博客标题得有吧,博客时间也得有吧,正文也得有吧,博客id也要有,因为后面点击这个查看全文,它要去数据库搜文章,而userId就无法搜文章,因为同一个用户写的文章可能不止一个。
🍀约定前后端交互接⼝

既然返回的是5个固定的属性,那么我们完全可以写个类嘛,

pojo实体类-----》response响应--------也就是实体类的响应。

至于为啥要加@Data注解,@JsonFormat注解,getContent方法,后面我们看业务层代码的时候我再讲理由,
🍀控制层

注入的是blogInfoService?不对,这是一个接口,并且也没交给spring进行管理,

那注入的是啥呢,其实是blogInfoService接口的实现类了。

回到控制层那里,调用的下面这个方法。

业务层

无疑就是从一个对象转化成另一个对象了,其中我标五角星的那个我们一起去看看。

其中BeanUtils.copyProperties(blogInfo,blogInfoResponse);方法,拿到bloginfo对象的值赋给bloginfoResponse对象,咋赋值呢,自然是通过@Data注解里的setter方法赋值,
至于我们为啥要写getContent方法,那是因为我们这个那是因为json序列化返回的时候,它要获取对象里的值,就需要get方法获取,而我们博客列表页面只显示部分正文了。
最后@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")可以理解为我们指定了json我显示的数据格式是这样子的,你就不要乱搞默认啥的。
由于我们这里用的是mybatis-plus,service层就直接调用查询了数据库了,就不写数据层了。
🍀客户端代码
java
$.ajax({
type:"get",
url:"/blog/getList",
success: function(result){
if(result.code==200&&result.data!=null){
let finalHtml="";
for(let blog of result.data){
finalHtml+='<div class="blog">';
finalHtml+='<div class="title">'+blog.title+'</div>';
finalHtml+='<div class="date">'+blog.updateTime+'</div>';
finalHtml+='<div class="desc">'+blog.content+'</div>';
finalHtml+='<a class="detail" href="blog_detail.html?blogId='+blog.id+'">查看全文>></a>';
finalHtml+='</div>';
}
$(".container .right").html(finalHtml);
}
}
});
我给大家顺下逻辑哈,后端返回给前端数据,前端先校验是否success,也就是200状态码,然后再看里面我们自己手动设置的code是200不,data数据空不空啊,然后拼接html页面,然后不是有个点击查看全文按钮嘛,说明是个超链接,需要博客的id来定位查询那篇博客的正文的相关信息啊,最后html片段赋值在恰当位置。
所以第一个接口写完了,难不,不能这么讲,细节很多,简单不,也不简单,因为我们只是会用一点点而已,底层的东西,源码分析啥的,json序列化啥的,说实现,我一知半解的,所以说,只是站在巨人的肩膀上,同志仍需努力。
🍁实现博客详情
🍀约定前后端交互接⼝

和博客列表的接口文档一样,我们这里偷了个懒,这里userId要用到,id其实不要返回都行,

为啥需要返回userId呢,我们登录完之后,前端就知道我们的userId了,而博客详情呢,又是有编辑和删除按钮,它必须是登录人和这篇博客的作者是同一个人才能显示的,而我们如何确定两者是同一个人呢,只能是userId唯一标识才能确定。
🍀控制层
java
@GetMapping("/getBlogDetail")
public BlogInfoResponse2 getBlogDetail(@NotNull(message="blogId 不能为空") Integer blogId){
log.info("获取博客详情,blogId:{}",blogId);
return blogInfoService.getBlogDetail(blogId);
}
@NotNull注解检验单参是否为null,为null就报MethodArgumentNotValidException异常,不过我们在统一异常处理那块给处理好了。
🍀业务层

不多说,和博客列表的那个逻辑很像
🍀直接客户端代码吧
java
$.ajax({
type:"get",
url:"/blog/getBlogDetail"+location.search,
success:function(result){
//TODO 校验不全面
if(result.code==200&&result.data!=null){
let blogInfo=result.data;
$(".right .content .title").text(blogInfo.title);
$(".right .content .date").text(blogInfo.updateTime);
//$(".right .content .detail").text(blogInfo.content);
editormd.markdownToHTML("detail",{
markdown:blogInfo.content
});
let loginUserid=localStorage.getItem("login_userid");
let html ='';
if(blogInfo.userId==loginUserid){
html +='<div class="operating">';
html +='<button onclick="window.location.href=\'blog_update.html?blogId='+location.search+'\'">编辑</button>';
html +='<button onclick="deleteBlog()">删除</button>';
html +='</div>';
html +='';
}
$(".right .content").append(html);
}
},
});
$(".right .content .title").text(blogInfo.title);
$(".right .content .date").text(blogInfo.updateTime);
这两行代码是标题和时间的显示,
editormd.markdownToHTML("detail",{
markdown:blogInfo.content
});
这个就是正文的显示了,至于为啥会这样显示,这是前端markdown格式显示的问题哈哈,大家感兴趣可以去查查看。
下面的判断if(blogInfo.userId==loginUserid)来决定要不要显示编辑和删除按钮。
🍁实现登录
登录这里我们使用JWT令牌。
不过,需要先引入些以下依赖。
XML
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
生成令牌
java
/*
生成key
*/
private static final String secretString="e4roQ6HFcMUHGAcBS5Ps6kuq1Ntnau/VP7bzGw8vJts=";//这个也叫签名
private static final Key key= Keys.hmacShaKeyFor(secretString.getBytes());
private static final long Expiration=7*24*60*60*1000;//7天
/*
生成令牌
*/
public static String genJwt(Map<String,Object> claim){
/*
固定写法,生成token
*/
return Jwts.builder().setClaims(claim)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis()+Expiration))
.signWith(key)//签名算法
.compact();
}
我给大家过下逻辑,先得要个key,起始时间,截至时间,数据载荷claim,这4个最终生成token。也就是令牌就生成了。
校验令牌
java
/*
校验令牌
*/
public static Claims parseJwt(String jwt){
if(!StringUtils.hasText(jwt)){
return null;
}
//校验token是否合法
//创建解析器,设置签名,密钥
JwtParser jwtParser=Jwts.parserBuilder().setSigningKey(key).build();
//解析token
Claims claims=null;
try{
claims=jwtParser.parseClaimsJws(jwt).getBody();
}catch(Exception e){
log.warn("解析令牌失败,jwt:{}",jwt);
}
return claims;
}
用对应的签名去创建对应的解析器,然后去校验token(jwt),如果报异常了,就是不合法的token令牌,没报异常就是合法的令牌。
🍀约定前后端交互接⼝

返回的data里有userId和token两个东东,userId用户唯一身份id,token则交与前端保管,配合拦截器校验,token,检查是否登录,当然这个拦截器的逻辑是强制登陆接口的事哈哈。

🍀控制层

由于前端传递过来的是userName和password,所以我们也可以用一个对象来接收
java
@Data
public class UserLoginRequest {
@NotBlank(message = "用户名不能为空")
@Length(max=20,message="用户名长度不能超过20")
private String userName;
@NotBlank(message = "密码不能为空")
@Length(max=20,message="密码长度不能超过20")
private String password;
}
@Validated注解表示要按照对象里写的的校验规则来,@RequestBody注解不用多讲。
🍀业务层
java
@Override
public UserLoginResponse login(UserLoginRequest request) {
/*
1.先验证密码是否正确
2.如果正确,生成token,并返回
3.如果不正确,返回错误信息
*/
UserInfo userInfo=selectUserInfoByName(request.getUserName());
if(userInfo==null||userInfo.getId()==null){
throw new BlogException("用户名不存在");
}
// if(!request.getPassword().equals(userInfo.getPassword())){
// throw new BlogException("密码不存在");
// }
if(!SecurityUtils.verify(request.getPassword(),userInfo.getPassword())){
throw new BlogException("密码不正确");
}
//账号密码正确,claim载体
Map<String,Object> claim=new HashMap<>();
claim.put("id",userInfo.getId());
claim.put("name",userInfo.getUserName());
//生成token
String token= JwtUtils.genJwt(claim);
return new UserLoginResponse(userInfo.getId(),token);
}
这个接口只是生成了token,并没有校验,
🍀客户端代码
java
$.ajax({
type:"post",
url:"/user/login",
contentType:"application/json",
data: JSON.stringify({
userName:$("#username").val(),
password:$("#password").val()
}),
success:function(result){
//TODO 只写了核心条件判断
if(result!=null&&result.code==200&&result.data!=null){
let response=result.data;
localStorage.setItem("user_token",response.token);
localStorage.setItem("login_userid",response.userId);
location.href="blog_list.html";
}else{
alert(result.errMsg);
}
}
})
JSON.stringify-----json格式化,这里的逻辑就是赋值嘛,然后
localStorage.setItem("user_token",response.token);
localStorage.setItem("login_userid",response.userId);
这两行代码,是存在浏览器里面,如下

🍁实现强制登陆
顾名思义,需要用到拦截器,令牌校验。

我们每个前端代码都引了common.js,里面的上面的这个代码表示每次向后端发起请求的时候,都会设置header请求头,携带user_token数值。
🍀添加拦截器
java
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Autowired
private ObjectMapper objectMapper;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
response.setContentType("application/json;charset=utf-8");//要提前设置返回类型
//从header中获取token
String jwtToken=request.getHeader("user_token");
log.info("从header中获取token:{}",jwtToken);
//校验token
Claims claims= JwtUtils.parseJwt(jwtToken);
if(claims==null){
log.error("令牌校验失败,token:{}",jwtToken);
response.setStatus(HttpStatus.UNAUTHORIZED.value());//401状态码
response.getOutputStream().write(objectMapper.writeValueAsString(Result.fail("用户未登录")).getBytes());
return false;
}
log.info("令牌校验通过");
return true;
}
}
实现HandlerInterceptor接口,重写preHandle方法不用多说。
至于校验逻辑,无非就是校验header里的user_token能否正确校验出来。
🍀配置拦截路径
java
@Configuration
public class AppConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
List<String> excludePath=List.of(
"/user/login",
"/**.html",
"/blog-editormd/**",
"/css/**",
"/js/**",
"/pic/**",
"favicon.ico"
);
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/**")
.excludePathPatterns(excludePath);
}
}
实现WebMvcConfigurer接口,重写addInterceptors方法不用多说,我们只针对请求接口进行拦截,那些请求静态html页面不拦截,确保前端显示正常。
🍀客户端代码
java
$(document).ajaxError(function(event,xhr,options,exc){
if(xhr.status==400){
alert("参数校验失败");
}
if(xhr.status==401){
alert("您未登录,请返回到登录页面进行登录");
location.href="blog_login.html";
}
});
不通过就直接跳转到登录页面。为啥是401未登录,是因为上面我的拦截器设置了状态码为401.
🍁实现显示用户信息
如下,博客列表页面有,博客详情页面也有!

🍀约定前后端交互接口
两个接口文档
1.

2.

这个响应也完全可以写成一个对象

🍀控制层
java
@GetMapping("/getUserInfo")
public UserInfoResponse getUserInfo(@NotNull Integer userId){
return userInfoService.getUserInfo(userId);
}
@GetMapping("/getAuthorInfo")
public UserInfoResponse getAuthorInfo(@NotNull Integer blogId){
return userInfoService.getAuthorInfo(blogId);
}
@NotNull注解不必多说,报异常--统一异常处理也写好了。
java
@ResponseStatus(code= HttpStatus.BAD_REQUEST)
@ExceptionHandler(exception = {MethodArgumentNotValidException.class,HandlerMethodValidationException.class})
public Result handler(Exception e){
log.error("发生异常,e{}",e.getMessage());
return Result.fail("参数校验失败");
}
其中MethodArgumentNotValidException捕获属性异常例如:@NotNull所报的异常
而HandlerMethodValidationException捕获对象异常例如:@Validated所报的异常
🍀业务层


🍀客户端代码
博客列表的
java
let url="/user/getUserInfo?userId="+localStorage.getItem("login_userid");
function getUserInfo(url){
$.ajax({
type:"get",
url:url,
success:function(result){
if(result!=null&&result.code==200&&result.data!=null){
let userInfo=result.data;
$(".left .card h3").text(userInfo.userName);
$(".left .card a").atter("herf",userInfo.githubUrl)
}else{
alert(result.errMsg);
}
}
});
}
这个是获取前端自己存的
博客详情的
java
let url="/user/getAuthorInfo"+location.search;
function getUserInfo(url){
$.ajax({
type:"get",
url:url,
success:function(result){
if(result!=null&&result.code==200&&result.data!=null){
let userInfo=result.data;
$(".left .card h3").text(userInfo.userName);
$(".left .card a").atter("herf",userInfo.githubUrl)
}else{
alert(result.errMsg);
}
}
});
}
这个是获取url里的blogid的
🍁实现用户退出
这个较为简单,就是用户点击注销按钮之后,就跳转到登录页面,并且删除存储的user_token和login_userid。
java
function logout(){
localStorage.removeItem("user_token");
localStorage.removeItem("login_userid");
location.href="blog_login.html";
}
我编辑和删除和发布博客的3个接口就不写了,套路是一样的,我最后讲个加密/加盐吧,主要有点坐不住了哈哈。
🍁加密/加盐
🍀加密
java
/*
加密
password 用户输入的密码
return 盐值+密文
*/
public static String encrpt(String password){
//盐值--随机生成的--32位长度的
String salt= UUID.randomUUID().toString().replace("-","");
//数据库种存储的值
//md5(盐值+明文)->密文
//数据库中存储:密文+盐值
//这个是密文==也就是(盐值+明文)经过md5算法后得到的值--密文也是为32位长度的
String finalPassword=DigestUtils.md5DigestAsHex((salt+password).getBytes(StandardCharsets.UTF_8));
//数据库中存储:盐值+密文
return salt+finalPassword;
}
先随机生成盐值,然后盐值+明文---》md5算法生成一个密文,最后数据库存储这个密文
🍀校验
java
/*
解密--密码的验证
sqlPassword--数据库存储的 盐值+密文
*/
public static boolean verify(String inputPassword,String sqlPassword) {
if(!StringUtils.hasText(inputPassword)||!StringUtils.hasText(sqlPassword)){
return false;
}
if(sqlPassword.length()!=64){
return false;
}
String salt=sqlPassword.substring(0,32);
String finalPassword=DigestUtils.md5DigestAsHex((salt+inputPassword).getBytes(StandardCharsets.UTF_8));
//判断是否相等
return sqlPassword.equals(salt+finalPassword);
}
通过比对密码和数据库存储的密文,来判断是否密码正确,逻辑是这样的,先取到盐值,然后盐值+输入的密码---》经过md5算法得到密文,最后和数据库的比对即可。
完结