基于Spring实现博客项目

访问地址:用户登录

代码获取:基于Spring实现博客项目: Spring项目写博客项目 

 一.项目开发

1.项目开发阶段

  1. 需求评审,需求分析
  2. 项目设计(接口设计,DB设计等,比较大的需求,需要设计流程图,用例图,UML, model中的字段)
  3. 开发+自测
  4. 提测(提交测试)
  5. 验收:预发布环境/预生产环境部署测试(开发,测试,产品)
  6. 上线
     

2.前端页面 

1.登录页面: 根据用户名和密码,进行登录
2.博客列表页:显示所有博客列表,以及显示登录用户的个人信息                                                      3.博客详情页:显示当前博客的详细信息,以及作者信息
4.博客插入/编辑页

3.需求分析

1.登录接口(根据用户名和密码,来判断是否登录成功)                                                                       2.根据用户ID,获取用户相关信息
3.获取所有的博客列表
4.根据博客ID,获取博客的详情信息(作者ID)                                                                                     5.根据博客ID,更新博客内容
6.插入博客
7.删除博客

4.数据库设计

        --建表sqlcreate database if not exists `java_blog_spring` charset utf8mb4;--用户表drop table if exists `java_blog_spring`.`user`;create table `java_blog_spring`.`user` (`id` int not null auto_increment,`user_name` varchar(128) not null,`password` varchar(128) not null,`github_url` varchar(128) null,`delete_flag` tinyint(4) null default 0,`create_time` timestamp null default current_timestamp(),primary key (`id`),unique index `user_name_unique` (`user_name` asc))engine = innodb default character set = utf8mb4 comment = '⽤户表';--博客表drop table if exists `java_blog_spring`.`blog`;create table `java_blog_spring`.`blog` (`id` int not null auto_increment,`title` varchar(200) null,`content` text null,`user_id` int(11) null,`delete_flag` tinyint(4) null default 0,`create_time` timestamp null default current_timestamp(),primary key (`id`))engine = innodb default charset = utf8mb4 comment = '博客表';--新增用户信息insert into `java_blog_spring`.`user` (`user_name`, `password`,`github_url`)values("zhangsan","123456","https://gitee.com/bubble-fish666/class-java45");insert into `java_blog_spring`.`user` (`user_name`, `password`,`github_url`)values("lisi","123456","https://gitee.com/bubble-fish666/class-java45");insert into `java_blog_spring`.`blog` (`title`,`content`,`user_id`) values("第一篇博客","111我是博客正文我是博客正文我是博客正文",1);insert into `java_blog_spring`.`blog` (`title`,`content`,`user_id`) values("第二篇博客","222我是博客正文我是博客正文我是博客正文",2);

二.Java项目

1.创建Spring项目

 创建好之后为以下页面

2.创建实体类

 用户实体类

@Data
public class User {private Integer id;private String userName;private String password;private String githubUrl;private Byte deleteFlag;private Date createTime;
}

博客实体类 

@Data
public class Blog {private Integer id;private String title;private String content;private Integer userId;private Byte deleteFlag;private Date createTime;
}

3.创建Mapper

userMapper.java

@Mapper
public interface UserMapper {@Select("select * from user where id=#{id}")User selectById(Integer id);@Select("select * from user where user_name=#{name}")User selectByName(String name);
}

userMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.javastudy.blog_spring.mapper.UserMapper"></mapper>

blogMapper.java

@Mapper
public interface BlogMapper {@Select("select * from blog where delete_flag=0")List<Blog> selectAll();@Select("select * from blog where id=#{id} and delete_flag=0")Blog selectById(Integer id);Integer updateBlog(Blog blog);@Insert("insert into blog(content,title,user_id) values(#{content},#{title},#{userId})")Integer insertBlog(Blog blog);
}

 blogMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.javastudy.blog_spring.mapper.BlogMapper"><update id="updateBlog">update blog<set><if test="title!=null">title=#{title},</if><if test="content!=null">content=#{content},</if><if test="userId!=null">user_id=#{userId},</if><if test="deleteFlag!=null">delete_flag=#{deleteFlag},</if></set>where id=#{id};</update></mapper>

4.配置文件

application.yml

spring:profiles:active: dev# 日志信息
logging:file:path: logs/level:root: info

application-dev.yml

server:port: 8080# 数据库连接配置
spring:datasource:url: jdbc:mysql://localhost:13306/java_blog_spring?characterEncoding=utf8&useSSL=falseusername: rootpassword: woaini520driver-class-name: com.mysql.cj.jdbc.Driver#  mybatis xml 配置路径
mybatis:mapper-locations: classpath:mapper/**Mapper.xmlconfiguration: # 配置打印 MyBatis 执行的 SQLlog-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-underscore-to-camel-case: true  #驼峰转换

application-prod.yml

server:port: 8080# 数据库连接配置
spring:datasource:url: jdbc:mysql://localhost:3306/java_blog_spring?characterEncoding=utf8&useSSL=falseusername: rootpassword: woaini520driver-class-name: com.mysql.cj.jdbc.Driver#  mybatis xml 配置路径
mybatis:mapper-locations: classpath:mapper/**Mapper.xmlconfiguration:map-underscore-to-camel-case: true

5.测试类

userMapper

@SpringBootTest
@Slf4j
class UserMapperTest {@AutowiredUserMapper userMapper;@Testvoid selectById() {User user = userMapper.selectById(1);log.info(user.toString());}@Testvoid selectByName() {User user = userMapper.selectByName("zhangsan");log.info(user.toString());}
}

 

blogMapper

@SpringBootTest
@Slf4j
class BlogMapperTest {@AutowiredBlogMapper blogMapper;@Testvoid selectAll() {List<Blog> blogs = blogMapper.selectAll();log.info(blogs.toString());}@Testvoid selectById() {Blog blog = blogMapper.selectById(1);log.info(blog.toString());}@Testvoid updateBlog() {Blog blog = new Blog();blog.setId(1);blog.setTitle("测试的第一篇博客");blog.setTitle("测试的第一篇博客的正文内容");blogMapper.updateBlog(blog);}@Testvoid insertBlog() {Blog blog = new Blog();blog.setTitle("第三篇博客");blog.setContent("第三篇博客的正文内容");blog.setUserId(1);blogMapper.insertBlog(blog);}
}

 

 

 6.Common包

1.Result

@Data
public class Result {//业务处理状态码 200成功 <=0表示失败  (注意与请求状态码区分)private Integer code;//业务返回信息private String msg;//业务数据private Object data;/*** 业务处理失败** @param code* @param message* @return*/public static Result fail(Integer code, String message) {Result result = new Result();result.setCode(code);result.setMsg(message);result.setData("");return result;}public static Result fail(Integer code, String message, Object data) {Result result = new Result();result.setCode(code);result.setMsg(message);result.setData(data);return result;}public static Result success(Object data) {Result result = new Result();result.setCode(200);result.setMsg("");result.setData(data);return result;}public static Result success(String message, Object data) {Result result = new Result();result.setCode(200);result.setMsg(message);result.setData(data);return result;}}

2.ErrorAdvice(统一异常返回)

@ControllerAdvice
public class ErrorAdvice {@ExceptionHandlerpublic Result error(Exception e) {return Result.fail(-1, e.getMessage());}
}

3.统一返回格式处理 

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}@SneakyThrows@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {if (body instanceof Result) {return body;}if (body instanceof String) {ObjectMapper objectMapper = new ObjectMapper();return objectMapper.writeValueAsString(Result.success(body));}return Result.success(body);}}

7.导入前端代码

前端代码在这取:基于Spring实现博客项目: Spring项目写博客项目

三.业务代码

1.约定前后端交互接口

[请求]
/blog/getlist
[响应]
[
 {
 blogId: 1,
 title: "第⼀篇博客",
 content: "博客正⽂",
 userId: 1,
 postTime: "2021-07-07 12:00:00"
 },
 {
 blogId: 2,
 title: "第⼆篇博客",
 content: "博客正⽂",
 userId: 1,
 postTime: "2021-07-07 12:10:00"
 },

 

2.Service层

UserService

@Service
public class UserService {@Autowiredprivate UserMapper userMapper;@Autowiredprivate BlogMapper blogMapper;public User selectById(Integer id) {return userMapper.selectById(id);}public User selectByName(String name) {return userMapper.selectByName(name);}public User getAuthorInfoByBlogId(Integer id) {Blog blog = blogMapper.selectById(id);if (blog == null || blog.getUserId() < 0) {return null;}return userMapper.selectById(blog.getUserId());}
}

BlogService

@Service
public class BlogService {@Autowiredprivate BlogMapper blogMapper;public List<Blog> getAll() {return blogMapper.selectAll();}public Blog getBlogById(Integer id) {return blogMapper.selectById(id);}public Integer updateBlog(Blog blog) {return blogMapper.updateBlog(blog);}public Integer addBlog(Blog blog) {return blogMapper.insertBlog(blog);}}

3.Controller层

BlogController

@RestController
@RequestMapping("/blog")
public class BlogController {@AutowiredBlogService blogService;@RequestMapping("/getlist")public List<Blog> getBlogList() {return blogService.getAll();}@RequestMapping("/getBlogDetail")public Result getBlogDetail(Integer id, HttpSession httpSession) {if (id == null || id < 0) {return Result.fail(-1, "非法的参数");}Blog blog = blogService.getBlogById(id);User user = (User) httpSession.getAttribute(Constants.USER_INFO_SESSION);if (blog.getUserId() == user.getId()) {blog.setIsLoginUser(true);}return Result.success(blog);}@RequestMapping("/add")public Result addBlog(String title, String content, HttpSession httpSession) {if (!StringUtils.hasLength(title) || !StringUtils.hasLength(content)) {return Result.fail(-1, "内容不能为空");}User user = (User) httpSession.getAttribute(Constants.USER_INFO_SESSION);if (user == null || user.getId() < 0) {return Result.fail(-1, "用户不存在");}Blog blog = new Blog();blog.setContent(content);blog.setTitle(title);blog.setUserId(user.getId());blogService.addBlog(blog);return Result.success(true);}@RequestMapping("/update")public Result updateBlog(Blog blog) {if (!StringUtils.hasLength(blog.getContent()) || !StringUtils.hasLength(blog.getTitle()) || blog.getId() == null) {return Result.fail(-1, "内容不能为空");}blogService.updateBlog(blog);return Result.success(true);}@RequestMapping("/delete")public Result deleteBlog(@RequestParam("id") Integer blogId) {if (blogId == null || blogId < 0) {return Result.fail(-1, "博客id不合法或者为空");}Blog blog = new Blog();blog.setId(blogId);blog.setDeleteFlag((byte) 1);blogService.updateBlog(blog);return Result.success(true);}
}

UserController

@RestController
@RequestMapping("/user")
public class UserController {@AutowiredUserService userService;@RequestMapping("/login")public Result login(HttpServletRequest request, String username, String password) {//参数校验if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password)) {return Result.fail(-2, "账号或密码不能为空");}//密码校验User user = userService.selectByName(username);if (user == null || !user.getPassword().equals(password)) {return Result.fail(-3, "用户名不存在或者密码错误");}//参数返回user.setPassword("");HttpSession session = request.getSession(true);session.setAttribute(Constants.USER_INFO_SESSION, user);return Result.success("登陆成功");}@RequestMapping("/getUserInfo")public Result getUserInfo(HttpSession session) {if (session == null || session.getAttribute(Constants.USER_INFO_SESSION) == null) {return Result.fail(-1, "用户未登录");}return Result.success(session.getAttribute(Constants.USER_INFO_SESSION));}@RequestMapping("/getAuthorInfo")public Result getAuthorInfoByBlogId(@RequestParam("id") Integer blogId) {if (blogId == null || blogId < 0) {return Result.fail(-1, "id参数错误");}User user = userService.getAuthorInfoByBlogId(blogId);if (user == null) {return Result.fail(-1, "不存在文章作者");}user.setPassword("");return Result.success(user);}@RequestMapping("/logout")public Result logout(HttpSession session) {session.removeAttribute(Constants.USER_INFO_SESSION);return Result.success(true);}
}

4.登录接口拦截器 

@Component
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {HttpSession session = request.getSession(false);if (session == null || session.getAttribute(Constants.USER_INFO_SESSION) == null) {response.setStatus(401);return false;}return true;}
}
@Configuration
public class AppConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;private final List<String> excludes = Arrays.asList("/**/*.html","/blog-editormd/**","/css/**","/js/**","/pic/**","/user/login");@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns("/**"). //拦截所有路径excludePathPatterns(excludes);}
}

在blog_list.html和blog_detail的ajax请求添加

                error: function (error) {if (error != null && error.status == 401) {location.assign("/blog_login.html");}}

四.前端代码

有些代码重复出现,可以抽象为一个函数,我们放在./js/common.js中

function logout() {$("#logout").click(function () {$.ajax({type: "get",url: "/user/logout",success: function (result) {if (result != null && result.data == true) {location.assign("/blog_login.html")}},})})
}

1.blog_list.html

先来个前置知识:日期格式化

方式一:将日期格式改为(java.sql.Date适用)

private Timestamp createTime;

然后引入js包

function formatDate(time) {var date = new Date(time);var year = date.getFullYear(),month = date.getMonth() + 1,//月份是从0开始的day = date.getDate(),hour = date.getHours(),min = date.getMinutes(),sec = date.getSeconds();var newTime = year + '-' +(month < 10 ? '0' + month : month) + '-' +(day < 10 ? '0' + day : day) + ' ' +(hour < 10 ? '0' + hour : hour) + ':' +(min < 10 ? '0' + min : min) + ':' +(sec < 10 ? '0' + sec : sec);return newTime;
}

 直接进行转化即可

<script src="./js/common.js"></script>
formatDate(blog.createTime)

方式二:(java.util.Date适用)

工具类

public class DateUtils {public static String formatDate(Date date) {SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");return simpleDateFormat.format(date);}
}

博客实体类 

@Data
public class Blog {private Integer id;private String title;private String content;private Integer userId;private Byte deleteFlag;private Date createTime;public String getCreateTime() {return DateUtils.formatDate(createTime);}
}

此时就不需要多余的操作了

     finalHtml += '<div class="date">'+blog.createTime+'</div>';

之后javascrip代码

    <script src="./js/jquery.min.js"></script><script src="./js/common.js"></script><script>$(function () {$.ajax({type: "get",url: "/blog/getlist",success: function (result) {var finalHtml = "";if (result.code == 200 && result.data != null && result.data.length > 0) {var dataHtml = result.data;for (var i = 0; i < dataHtml.length; ++i) {var blog = dataHtml[i];finalHtml += '<div class="blog">';finalHtml += '<div class="title">' + blog.title + '</div>';finalHtml += '<div class="date">' + blog.createTime + '</div>';finalHtml += '<div class="desc">' + blog.content + '</div>';finalHtml += '<a class="detail" href="blog_detail.html?id=' + blog.id + '">查看全文&gt;&gt;</a>';finalHtml += '</div>';}$(".right").html(finalHtml);}},error: function (error) {if (error != null && error.status == 401) {location.assign("/blog_login.html");}}});$.ajax({type: "get",url: "/user/getUserInfo",success: function (result) {if (result != null && result.code == 200 && result.data != null) {$(".container .left .card h3").text(result.data.userName);$(".container .left .card a").attr("href", result.data.githubUrl)}},error: function (error) {if (error != null && error.status == 401) {location.assign("/blog_login.html");}}});logout();})</script>

2.blog_detail.html

    <script src="./js/jquery.min.js"></script><script src="blog-editormd/editormd.js"></script><script src="blog-editormd/lib/marked.min.js"></script><script src="blog-editormd/lib/prettify.min.js"></script><script src="js/common.js"></script><script>$(function () {$.ajax({type: "get",url: "/blog/getBlogDetail" + location.search,success: function (result) {if (result.code == 200 && result.data != null) {var blog = result.data;$(".title").text(blog.title);$(".date").text(blog.createTime);editormd.markdownToHTML("content", {markdown: blog.content,});if (result.data.isLoginUser == true) {var innerhtml = "";innerhtml += '<button onclick="window.location.href = \'blog_update.html?id=' + blog.id + '\'">编辑</button>';innerhtml += '<button onclick="deleteBlog()">删除</button>';$(".operating").html(innerhtml);}}},error: function (error) {if (error != null && error.status == 401) {location.assign("/blog_login.html");}}});$.ajax({type: "get",url: "/user/getAuthorInfo" + location.search,success: function (result) {if (result != null && result.code == 200 && result.data != null) {$(".container .left .card h3").text(result.data.userName);$(".container .left .card a").attr("href", result.data.githubUrl)}},error: function (error) {if (error != null && error.status == 401) {location.assign("/blog_login.html");}}});// jQuery("#deleteButton").click(function () {//     if (confirm("确定要删除吗?")) {//         $.ajax({//             type: "post",//             url: "/blog/delete" + location.search,//             success: function (result) {//                 if (result != null && result.data == true) {//                     location.assign("blog_list.html");//                 }//             }//         })//     }// });})function deleteBlog() {if (confirm("确定要删除吗?")) {$.ajax({type: "post",url: "/blog/delete" + location.search,success: function (result) {if (result != null && result.data == true) {location.assign("blog_list.html");}}})}};logout();</script>

3.blog_login.html

    <script src="./js/jquery.min.js"></script><script>$(function () {$("#submit").click(function () {//获取用户名var username = jQuery("#username");if (!username.val()) {alert("用户名不能为空");username.focus();return;}//获取密码var password = jQuery("#password");if (!password.val()) {alert("密码不能为空");password.focus();return;}$.ajax({type: "post",url: "/user/login",data: {username: username.val(),password: password.val()},success: function (result) {if(result.code==200){//跳转到主页location.href="blog_list.html";return;}else{//业务处理失败alert(result.msg);return;}},error: function () {}})})})</script>

4.blog_edit.html

    <script src="js/jquery.min.js"></script><script src="blog-editormd/editormd.min.js"></script><script type="text/javascript">$(function () {var editor = editormd("editor", {width: "100%",height: "550px",path: "blog-editormd/lib/"});$("#submit").click(function () {$.ajax({type: "post",url: "/blog/add",data: {title: $("#title").val(),content: $("#content").val()},success: function (result) {if (result != null && result.data != null && result.data == true) {location.assign("blog_list.html");}},error: function (result) {if (result != null && result.status == 401) {alert("请登录之后再进行操作");}}})})});</script>

5.blog_update.html

    <script src="js/jquery.min.js"></script><script src="blog-editormd/editormd.min.js"></script><script src="js/common.js"></script><script type="text/javascript">$(function () {var editor = editormd("editor", {width: "100%",height: "550px",path: "blog-editormd/lib/"});$.ajax({type: "get",url: "/blog/getBlogDetail" + location.search,success: function (result) {var blog = result.data;if (result != null && result.code == 200 && result.data != null) {$("#title").val(blog.title);$("#content").val(blog.content);$("#blogId").val(blog.id);}},error: function (result) {if (result != null && result.status == 401) {alert("请登录之后再进行操作");}}});$("#submit").click(function () {$.ajax({type: "post",url: "/blog/update",data: {title: $("#title").val(),content: $("#content").val(),id: $("#blogId").val()},success: function (result) {if (result != null && result.data == true) {location.assign("blog_list.html");}},error: function (result) {if (result != null && result.status == 401) {alert("请登录之后再进行操作");}}})})});</script>

五.加密措施

1.加密

假设我们的数据库被黑客进行劫持,那么用户的一些重要信息(比如密码,身份证号)就可能被获取,这样对用户是十分不利的,因此我们需要对数据库中一些重要的信息进行加密存储.

目前有许多的加密算法,包括可逆加密和非可逆加密,可逆加密在http和https的时候就有使用,通过密钥就可以使明文变为密文,同时也可以让密文变为明文,但是非可逆加密就不同了,非可逆加密只能使明文加密为密文,不能从密文变为明文,一般在数据库中我们采用非可逆加密.

常用的非可逆加密有MD5加密,通过对明文加密,可以得到长度固定的MD5值,MD5加密就可以得到32位或者16位的加密后的结果.

Java中使用MD5加密

@SpringBootTest
class BlogSpringApplicationTests {@Testvoid contextLoads() {String finalPassword = DigestUtils.md5DigestAsHex("123456".getBytes());System.out.println("第一次加密:" + finalPassword);finalPassword = DigestUtils.md5DigestAsHex("123456".getBytes());System.out.println("第二次加密:" + finalPassword);finalPassword = DigestUtils.md5DigestAsHex("123456".getBytes());System.out.println("第三次加密:" + finalPassword);}}

 可以观察到:MD5加密后得到的值是都是一样的,并且无论进行多少次MD5加密(对产生的MD5值多次进行加密),得到的结果都是一样的.

那么这样会不会产生安全问题呢?当然会!虽然说MD5加密是不可逆的加密,但是可以通过提前生成对应的明文和密文对应的表,然后通过需要破解的密文与之前生成表的密文进行对应,从而找到相应的明文,但是这种方法是十分低效的,但是也可以进行破解明文,尤其对于密码不复杂且短的很容易破解,那么怎么样可以避免这种情况呢?

首先可以在用户端进行,我们在设置的密码的时候,通常网站都要求需要字母与数字的组合,并且长度都要求大于一定的值,这样密码的安全等级很高,不容易被破解,(比如纯数字组合就10种,字母加数字就有26+10种,大小写字母加数字组合就有26*2+10种,长度越长组合自然也就越多).

接下来通过服务端通过加盐的方式存储密码.

2.盐值

假设用户的密码安全很低,如果在存储的时候将密码与随机的字符串的进行拼接,然后再通过MD5加密的方式进行存储的话,同样也可以时密码难以破解,并且可以通过生成多个不同的随机字符串,可以解决MD5不能实现多次加密的问题.随机生成的字符串也要存储到数据库中,通常与生成的MD5数值拼接存储.

代码展示,通过UUID生成随机的字符串.

    @Testvoid contextLoads() {String salt = UUID.randomUUID().toString();String finalPassword = DigestUtils.md5DigestAsHex(("123456" + salt).getBytes());System.out.println("第一次salt:" + salt);System.out.println("第一次加密:" + finalPassword);salt = UUID.randomUUID().toString();finalPassword = DigestUtils.md5DigestAsHex(("123456" + salt).getBytes());System.out.println("第二次salt:" + salt);System.out.println("第二次加密:" + finalPassword);salt = UUID.randomUUID().toString();finalPassword = DigestUtils.md5DigestAsHex(("123456" + salt).getBytes());System.out.println("第三次salt:" + salt);System.out.println("第三次加密:" + finalPassword);}

 我们不希望产生的salt含有特殊字符,因此我们可以通过以下的方式将"-"去掉

    @Testvoid contextLoads() {String salt = UUID.randomUUID().toString().replace("-", "");String finalPassword = DigestUtils.md5DigestAsHex(("123456" + salt).getBytes());System.out.println("第一次salt:" + salt);System.out.println("第一次加密:" + finalPassword);salt = UUID.randomUUID().toString().replace("-", "");finalPassword = DigestUtils.md5DigestAsHex(("123456" + salt).getBytes());System.out.println("第二次salt:" + salt);System.out.println("第二次加密:" + finalPassword);salt = UUID.randomUUID().toString().replace("-", "");finalPassword = DigestUtils.md5DigestAsHex(("123456" + salt).getBytes());System.out.println("第三次salt:" + salt);System.out.println("第三次加密:" + finalPassword);}

3.实现

public class SecurityUtils {/*** 将密码进行加密* 根据明文,返回密文(salt+MD5)** @param password* @return*/public static String encry(String password) {//生成盐值String salt = UUID.randomUUID().toString().replace("-", "");//进行加密String finalPassword = DigestUtils.md5DigestAsHex((password + salt).getBytes());return salt + finalPassword;}/*** @param inputPassword 输入的密码* @param finalPassword 数据库存储的密码* @return 输入的密码和存储的密码是否相同*/public static boolean decrypt(String inputPassword, String finalPassword) {if (!StringUtils.hasLength(inputPassword) || !StringUtils.hasLength(finalPassword)) {return false;}if (finalPassword.length() != 64) {return false;}String salt = finalPassword.substring(0, 32);String password = DigestUtils.md5DigestAsHex((inputPassword + salt).getBytes());return (salt + password).equals(finalPassword);}}

修改密码验证的接口

    @RequestMapping("/login")public Result login(HttpServletRequest request, String username, String password) {//参数校验if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password)) {return Result.fail(-2, "账号或密码不能为空");}//密码校验User user = userService.selectByName(username);if (user == null || !SecurityUtils.decrypt(password, user.getPassword())) {return Result.fail(-3, "用户名不存在或者密码错误");}//参数返回user.setPassword("");HttpSession session = request.getSession(true);session.setAttribute(Constants.USER_INFO_SESSION, user);return Result.success("登陆成功");}

六.上线发布

1.多平台开发

    <profiles><profile><id>dev</id><properties><env>dev</env></properties><activation><activeByDefault>true</activeByDefault></activation></profile><profile><id>prod</id><properties><env>prod</env></properties><activation><activeByDefault>false</activeByDefault></activation></profile></profiles>

如果需要跳过test,可以点击 

 application.yml文件

 此时打包即可

2.部署linux服务器 

1.创建数据库

可以将sql语句变成一个文件,然后执行下面的

 source /root/java78/create.sql

2.将代码打包

打包完成之后,将jar包拖拽到linux服务器上

3.运行代码 

 后台启动项目

nohup java -jar Blog_Spring-0.0.1-SNAPSHOT.jar &

 查看日志

cd logs/

tail -f spring.log

 

 终止当前的服务

ps -ef | grep [ ] 

 注意:如果开启多个服务,需要开端口,给防火墙添加端口号

查看防火墙状态(如果没开启,建议开启,不开启可以直接访问,开启了需要进行已下的操作访问)

systemctl status firewalld

 启动防火墙和关闭防火墙

systemctl start firewalld

systemctl stop firewalld

查看开放的端口号

firewall-cmd --list-ports

开启8080端口

firewall-cmd --permanent --add-port=8080/tcp

重启防火墙

firewall-cmd --reload

设置开机启动

systemctl enable firewalld

添加安全组

 否则无法正常访问

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/110437.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入浅出SSD:固态存储核心技术、原理与实战(文末赠书)

名字&#xff1a;阿玥的小东东 学习&#xff1a;Python、C/C 主页链接&#xff1a;阿玥的小东东的博客_CSDN博客-python&&c高级知识,过年必备,C/C知识讲解领域博主 目录 内容简介 作者简介 使用Python做一个计算器 本期赠书 近年来国家大力支持半导体行业&#xff0…

计算机视觉与人工智能在医美人脸皮肤诊断方面的应用

一、人脸皮肤诊断方法 近年来&#xff0c;随着计算机技术和人工智能的不断发展&#xff0c;中医领域开始逐渐探索利用这些先进技术来辅助面诊和诊断。在皮肤望诊方面&#xff0c;也出现了一些现代研究&#xff0c;尝试通过图像分析技术和人工智能算法来客观化地获取皮肤相关的…

循环购商业模式:提升复购率与用户价值的创新策略-微三云门门

亲爱的企业家们&#xff0c;我是微三云门门&#xff01;今天&#xff0c;我将为大家详细介绍一种颠覆性的商业模式&#xff1a;循环购商业模式。这个模式不仅可以帮助企业提升平台的复购率&#xff0c;还能够拉新用户并提升用户的消费率。让我们一起深入了解这个引人注目的商业…

Ubuntu 下安装Qt5.12.12无法输入中文解决方法

Ubuntu 下安装Qt5.12.12无法输入中文解决方法 一&#xff0c;环境&#xff1a; &#xff08;1&#xff09;VMware Workstation 15 Pro &#xff08;2&#xff09;Ubuntu 20.04 &#xff08;3&#xff09;Qt 5.12.12 64bits &#xff08;4&#xff09;Qt Creator 5.0.2 &#…

Hadoop Yarn 核心调优参数

文章目录 测试集群环境说明Yarn 核心配置参数1. 调度器选择2. ResourceManager 调度器处理线程数量设置3. 是否启用节点功能的自动检测设置4. 是否将逻辑处理器当作物理核心处理器5. 设置物理核心到虚拟核心的转换乘数6. 设置 NodeManager 使用的内存量7. 设置 NodeManager 节点…

ant-vue1.78版a-auto-complete表单自动搜索返回列表中的关键字标红

a-auto-complete表单自动搜索返回列表中的关键字标红 通常在做关键字标红的场景&#xff0c;都是后端返回html结构&#xff0c;前端直接渲染实现&#xff0c;但是如果需要前端处理的话&#xff0c;实现也是很简单的&#xff0c;接下来我直接上应用场景吧 应用场景就是通过关键…

GaussDB技术解读系列:高级压缩之OLTP表压缩

8月16日&#xff0c;第14届中国数据库技术大会&#xff08;DTCC2023&#xff09;在北京国际会议中心顺利举行。在GaussDB“五高两易”核心技术&#xff0c;给世界一个更优选择的专场&#xff0c;华为云数据库GaussDB首席架构师冯柯对华为云GaussDB数据库的高级压缩技术进行了详…

centos7搭建apache作为文件站后,其他人无法访问解决办法

在公司内网的一个虚拟机上搭建了httpsd服务&#xff0c;准备作为内部小伙伴们的文件站&#xff0c;但是搭建好之后发现别的小伙伴是无法访问我机器的。 于是寻找一下原因&#xff0c;排查步骤如下&#xff1a; 1.netstat -lnp 和 ps aux 先看下端口和 服务情况 发现均正常 2.…

淘宝商品数据采集(如何快速获取淘宝商品信息),淘宝API接口申请指南

淘宝作为国内的电商平台&#xff0c;拥有海量的商品信息。对于想要进行淘宝商品数据采集的人来说&#xff0c;如何快速获取淘宝商品信息是一个重要的问题。本文将介绍一些快速获取淘宝商品信息的方法。 1. 使用淘宝开放平台PI 淘宝开放平台提供了多种PI接口&#xff0c;可以通…

【微服务部署】01-Kubernetes部署流程

文章目录 部署1. Kubernetes是什么2. Kubernetes的优势3. 环境搭建4. 应用部署 部署 1. Kubernetes是什么 Kubernetes是一个用于自动部署、扩展和管理容器化应用程序的开源系统 2. Kubernetes的优势 自动化容器部署资源管理与容器调度服务注册发现与负载均衡内置配置与秘钥…

【java】【springboot】【idea】springboot项目pom.xml 灰色下划线

解决方案&#xff1a; 这里我们找到了原因&#xff0c;就是因为选择了Ignored Files导致pom.xml文件被设置在maven忽略文件清单中&#xff0c;所以我们将打勾的选项取消&#xff0c;点击Apply,然后点击OK

一文解析:共享WiFi项目到底怎么样呢?

大家都知道&#xff0c;现代社会已经离不开互联网的便利&#xff0c;而WiFi的普及更是提升了人们的生活质量和工作效率。然而&#xff0c;面对庞大的用户群体和不断增长的网络需求&#xff0c;无论人们到哪都是习惯性的连接上wifi。而共享WiFi的出现&#xff0c;正是满足了大众…

Linux基础(一)

1.操作系统概念 人与计算机交流的中介 管理和控制计算机中硬件和软件资源 处于上层应用程序和底层硬件之间的软件平台 2.操作系统组成 内核&#xff1a;直接控制管理硬件 内核直接识别计算机二进制语言 解释器&#xff1a;把c c java python等语言解释成二进制&#xff…

Leetcode每日一题:1267. 统计参与通信的服务器(2023.8.24 C++)

目录 1267. 统计参与通信的服务器 题目描述&#xff1a; 实现代码与解析&#xff1a; 写法一&#xff1a;两次遍历 hash 原理思路&#xff1a; 写法二&#xff1a;三次遍历 原理思路&#xff1a; 1267. 统计参与通信的服务器 题目描述&#xff1a; 这里有一幅服务器分…

215. 数组中的第K个最大元素

题目描述 给定整数数组 nums 和整数 k&#xff0c;请返回数组中第 **k** 个最大的元素。 请注意&#xff0c;你需要找的是数组排序后的第 k 个最大的元素&#xff0c;而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1: 输入: [3,2…

【Axure教程】调用日期选择器并筛选中继器表格

今天教大家在Axure里怎么调用代码调用浏览器的日期选择器并对对中继器表格进行日期区间的筛选。调用浏览器日期选择器的好处是&#xff0c;可以选择真实的日期&#xff0c;包括某年某月某日是星期几&#xff0c;哪个二月是29天……都是真实的&#xff0c;那不同的浏览器日期选择…

kafka复习:(22)一个分区只能被消费者组中的一个消费者消费吗?

默认情况下&#xff0c;一个分区只能被消费者组中的一个消费者消费。但可以自定义PartitionAssignor来打破这个限制。 一、自定义PartitionAssignor. package com.cisdi.dsp.modules.metaAnalysis.rest.kafka2023;import org.apache.kafka.clients.consumer.internals.Abstrac…

JDK配置环境变量(超详细)

先安装JDK再配置环境变量&#xff01; JDK可以简单理解为就是java&#xff0c;JDK包含了java项目运行所需要的运行环境JRE&#xff0c;编译运行java程序的java虚拟机JVM。 jdk-8u201-windows-x64安装包&#xff08;jdk1.8&#xff09;&#xff1a; 提取码&#xff1a;19xv …

外部库/lib/maven依赖项 三者关系

外部库(存放项目初始配置的jar包)(它的文件夹里并没有包含lib文件夹的引的外部的依赖的jar包) lib(存放外部导入到项目的依赖的jar包) maven依赖项(管理项目所有的jar包依赖) 三者存放jar包的关系 项目所依赖的全部的jar包 maven依赖项的jar包 外部库中的jar包 lib中的…

文件夹无法删除?简单3招,轻松解决问题!

“我电脑里有一个文件夹占用了很大的内存&#xff0c;我想将它删除来释放一些内存&#xff0c;但是根本没法删除&#xff0c;为什么会这样呢&#xff1f;文件夹无法删除应该怎么办呢&#xff1f;” 在日常电脑使用中&#xff0c;有时候会遇到文件夹无法删除的情况&#xff0c;这…