0


基于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.数据库设计

        --建表sql
        create 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-java4
        5");
        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=false
    username: root
    password: woaini520
    driver-class-name: com.mysql.cj.jdbc.Driver

#  mybatis xml 配置路径
mybatis:
  mapper-locations: classpath:mapper/**Mapper.xml
  configuration: # 配置打印 MyBatis 执行的 SQL
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true  #驼峰转换

application-prod.yml

server:
  port: 8080

# 数据库连接配置
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/java_blog_spring?characterEncoding=utf8&useSSL=false
    username: root
    password: woaini520
    driver-class-name: com.mysql.cj.jdbc.Driver

#  mybatis xml 配置路径
mybatis:
  mapper-locations: classpath:mapper/**Mapper.xml
  configuration:
    map-underscore-to-camel-case: true

5.测试类

userMapper

@SpringBootTest
@Slf4j
class UserMapperTest {
    @Autowired
    UserMapper userMapper;

    @Test
    void selectById() {
        User user = userMapper.selectById(1);
        log.info(user.toString());
    }

    @Test
    void selectByName() {
        User user = userMapper.selectByName("zhangsan");
        log.info(user.toString());
    }
}

blogMapper

@SpringBootTest
@Slf4j
class BlogMapperTest {
    @Autowired
    BlogMapper blogMapper;

    @Test
    void selectAll() {
        List<Blog> blogs = blogMapper.selectAll();
        log.info(blogs.toString());

    }

    @Test
    void selectById() {
        Blog blog = blogMapper.selectById(1);
        log.info(blog.toString());
    }

    @Test
    void updateBlog() {
        Blog blog = new Blog();
        blog.setId(1);
        blog.setTitle("测试的第一篇博客");
        blog.setTitle("测试的第一篇博客的正文内容");
        blogMapper.updateBlog(blog);
    }

    @Test
    void 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 {
    @ExceptionHandler
    public Result error(Exception e) {

        return Result.fail(-1, e.getMessage());

    }
}

3.统一返回格式处理

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @SneakyThrows
    @Override
    public 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 {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private 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 {
    @Autowired
    private 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 {
    @Autowired
    BlogService 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 {
    @Autowired
    UserService 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 {
    @Override
    public 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 {
    @Autowired
    private LoginInterceptor loginInterceptor;

    private final List<String> excludes = Arrays.asList(
            "/**/*.html",
            "/blog-editormd/**",
            "/css/**",
            "/js/**",
            "/pic/**",
            "/user/login"
    );

    @Override
    public 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 {

    @Test
    void 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生成随机的字符串.

    @Test
    void 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含有特殊字符,因此我们可以通过以下的方式将"-"去掉

    @Test
    void 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

添加安全组

否则无法正常访问

标签: spring java 后端

本文转载自: https://blog.csdn.net/qq_64580912/article/details/132028335
版权归原作者 允歆辰丶 所有, 如有侵权,请联系我们删除。

“基于Spring实现博客项目”的评论:

还没有评论