基于Spring实现博客项目

news2025/3/17 17:37:02

访问地址:用户登录

代码获取:基于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

添加安全组

 否则无法正常访问

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

iOS开发Swift-2-图片视图、App图标-赏月App

1.创建新项目 点击File - New - Project。 选择Single View App&#xff0c;点击Next。 填写文件信息&#xff0c;点击Next。 选择文件位置&#xff0c;点击Create。 修改App显示名称为 “赏月”。 2.设置背景色 选择Main&#xff0c;点击View界面&#xff0c;选择右边属性&…

7、监测数据采集物联网应用开发步骤(5.3)

监测数据采集物联网应用开发步骤(5.2) 静态配置库数据库调用&#xff0c;新建全局变量初始化类com.zxy.main.Init_Page.py #! python3 # -*- coding: utf-8 -Created on 2017年05月10日 author: zxyong 13738196011 from com.zxy.z_debug import z_debug from com.zxy.common…

ThreeJS 模型中内嵌文字

之前有过模型中内嵌html网页&#xff0c;地址☞threeJS 模型中加载html页面_threejs 加载dom元素_小菜花29的博客-CSDN博客 这次是纯粹的在模型中嵌入文本信息&#xff0c;进行简单的文字展示 展示效果图 1. 使用FontLoader文字加载器 引入文本json文件&#xff0c;代码如下…

会话技术之Cookie和Session

一、会话技术 1、概念 会话&#xff1a;一次会话包含多次请求和响应。一次会话&#xff1a;浏览器第一次给服务器资源发送请求&#xff0c;会话建立&#xff0c;直到有一方断开为止。 2、功能 用于在多次请求之间跟踪和管理用户状态&#xff0c;实现数据连续性、数据共…

掉了无数头发成地中海后,我整理出了这套40+的大屏模板,快收藏!

最近又有不少粉丝后台问我接不接做可视化大屏&#xff0c;看来可视化大屏是越来越火啦&#xff0c;但老李还是要说一下&#xff0c;老李本身工作就很忙&#xff0c;实在是顾不过来&#xff0c;但老李会在自己体验过后为大家挑选合适的工具和模板&#xff0c;提升大家做大屏的效…

『PyQt5-Qt Designer篇』| 07 Qt Designer中栅格布局和表单布局的使用

07 Qt Designer中栅格布局和表格布局的使用 1 栅格布局1.1 按钮布局1.2 栅格布局中拖入控件1.3 保存并调用2 表单布局2.1 标签+输入控件2.2 保存并调用3 组合水平和垂直布局1 栅格布局 1.1 按钮布局 拖入几个按钮,如图: 选中所有按钮,右键点击布局-栅格布局: 之后可以看到…

日志开源组件(六)Adaptive Sampling 自适应采样

业务背景 有时候日志的信息比较多&#xff0c;怎么样才可以让系统做到自适应采样呢&#xff1f; 拓展阅读 日志开源组件&#xff08;一&#xff09;java 注解结合 spring aop 实现自动输出日志 日志开源组件&#xff08;二&#xff09;java 注解结合 spring aop 实现日志tr…

navicat连接数据库的方法(易懂)

1.首页要先下载Navicat 官网下载即可 2.下载完点击进入 找到左上角的连接 3.点击选择MySQL... 4.点击进入开始连接数据库

Linux常用命令——declare命令

在线Linux命令查询工具 declare 声明或显示shell变量 补充说明 declare命令用于声明和显示已存在的shell变量。当不提供变量名参数时显示所有shell变量。declare命令若不带任何参数选项&#xff0c;则会显示所有shell变量及其值。declare的功能与typeset命令的功能是相同的…

XPloteCAD开发实录-第一阶段

在该解阶段,主要的工作内容: 1.完成了框架引擎的设计代码设计工作; 2.完成了矩阵库,线性,微分几何等第三方数学库的封装; 3.完成了XPloteFrameWork 等设计和代码,里面包含不限于AutoFac,AutoMap,Serilog等封装以及各种模块的工具化; 这是目前用这个框架搭建完成的操作界面:…

IDEA遇到 git pull 冲突的几种解决方法

1 忽略本地修改&#xff0c;强制拉取远程到本地 主要是项目中的文档目录&#xff0c;看的时候可能多了些标注&#xff0c;现在远程文档更新&#xff0c;本地的版本已无用&#xff0c;可以强拉 git fetch --all git reset --hard origin/dev git pull关于commit和pull的先后顺…

iTOP-STM32MP157开发板应用层和内核层传递数据

我们的应用层和内核层是不能直接进行数据传输的。我们要想进行数据传输&#xff0c;要借助下面的这两个函数。 static inline long copy_from_user(void *to, const void __user * from, unsigned long n) static inline long copy_to_user(void __user *to, const void *fro…

基于java Swing 和 mysql实现的购物管理系统(源码+数据库+说明文档+运行指导视频)

一、项目简介 本项目是一套基于java Swing 和 mysql实现的购物管理系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、项目文档、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过…

他们朝我扔泥巴(scratch)

前言 纯~~~属~~~虚~~~构~~~&#xff08;同学看完短视频要我做&#xff0c;蟹蟹你&#xff09; 用scratch做的&#xff0c;幼稚得嘞(&#xffe3;_&#xffe3;|||)呵呵&#xff08;强颜欢笑&#xff09; 完成视频 视频试了好久&#xff0c;就是传不上来&#xff0c;私信我加我…

19 个最佳Three.JS 示例

推荐&#xff1a;使用 NSDT编辑器快速搭建3D应用场景 在浏览器中创建动画三个JS模型创建 3D 动画文本从 3D 图像创建 2D 模型制作 3D 模型动画添加 3D 效果创建 3D 游戏和交互式体验编程 3D 虚拟现实体验将颜色应用于 3D 几何体控制 3D 渲染性能与 3D 环境交互修改 3D 环境的照…

向量数据库(第 4 部分):分析权衡

在本系列的上一篇文章中&#xff0c;我们介绍了向量数据库中通常使用的不同类型的索引。然而&#xff0c;索引只是向量数据库中更大问题中的一小部分。回想一下&#xff0c;在第二部分中&#xff0c;我们描述了什么是向量数据库。为了区分目前市场上的各种向量数据库产品&#…

19.(地图工具篇)ArcMap合并与分割Shape

地图之家总目录&#xff08;订阅之前必须详细了解该博客&#xff09; 一&#xff1a;Arcgis合并shape文件 1.使用Merge工具 2.配置 3.等待合并完成 二&#xff1a;Arcgis分割shape文件 1&#xff1a;选择split by attribute工具 2:配置&#xff08;根据COUNTYNAME分割…

看这里,iOS备忘录恢复的3个简单高效方法

想问iPhone用户们一个问题&#xff1a;你们知道手机上哪个软件最了解自己吗&#xff1f;答案是&#xff1a;ios备忘录。为什么说是备忘录呢&#xff1f;因为备忘录记录了大家各种软件的账号密码、日常计划、朋友的生日&#xff0c;甚至是非常重要的银行卡密码。 由此看来&…

QT6添加第三方模块的cmake配置和qmake配置(以串口模块qserialport为例)

参考1&#xff0c;参考2 qmake建立的工程&#xff1a;https://mar-sky.blog.csdn.net/article/details/132487461&#xff0c; 模块安装&#xff1a;https://mar-sky.blog.csdn.net/article/details/132483421 简单的使用介绍 在qmake创建的项目工程中&#xff0c;使用外部模…

国标视频融合云平台EasyCVR视频汇聚平台的应用场景及其功能说明

一、平台简介 EasyCVR国标视频融合云平台是一款基于端-边-云一体化架构的视频融合AI智能分析网关平台。EasyCVR平台支持视频汇聚、融合管理&#xff0c;兼容多类型设备、多协议接入。其提供的视频功能包括&#xff1a;视频监控、无插件直播录像、云存储、检索回放、智能告警、…