汕头电商网站建设,金汇网站建设,wordpress设置固定连接没法访问了,国外申请域名的网站目录
一、项目简介 二、项目整体架构
数据库模块
后端模块
前端模块 三、项目具体展示 四、项目的具体实现
1、一些准备工作
#x1f34e;数据库、数据表的创建
#x1f34e;设置数据库和MyBatis的配置
#x1f34e;将前端项目引入到当前项目中
2、登录注册模块
数据库、数据表的创建
设置数据库和MyBatis的配置
将前端项目引入到当前项目中
2、登录注册模块
实体类的创建
前端后端交互
后端流程 登录功能的实现和注册大同小异
3、统一功能的处理
统一异常处理
统一数据格式返回
统一用户的登录验证用户登录拦截器
过程中遇到的bug
4、博客列表页面的实现更新中...)
5、博客详情页面的实现
6、博客的修改和删除功能
7、博客列表分页功能的实现
8、随机加盐的实现 一、项目简介
项目名称个人博客系统 主要操作的对象是文章和用户用户可在该系统上发表自己的博客查看自己或别人已经发表的文章 需要用到两张表userinfo(用户表、articleinfo文章表
需要实现的功能 登录注册 博客的分页列表功能 新增发表博客 修改、删除自己的博客 项目技术栈 SSMSpringBoot SpringMVC MyBatis MySQL jQuery 项目亮点 手动对用户密码实现随机加盐 统一异常处理、拦截器 用户登录持久化session内存 分页功能 二、项目整体架构
数据库模块
两张表用户表 文章表 后端模块 控制层controller包——》控制器 服务层service包——》服务类 持久层--数据访问层java目录下mapper类 resources目录下的mapper.xml——》mapper 实体层model包——》实体类 工具层config包util包——》统一异常处理、统一返回、随机加盐 前端模块
前端设计到7个页面 login.html登录页 reg.html注册页 blog_list.html总的博客列表页——》用到了blog_l myblog_list.html个人博客列表页 blog_content.html博客详情页 blog_edit.html博客编辑页 blog_update.html博客修改页 三、项目具体展示 项目公网地址登陆页面 登录页面、注册页面 总的博客列表页面 博客详情页 个人博客主页 博客修改页面 博客编辑页面 项目源码java_spring: SpringMVC、SpringBoot、MyBatis学习 - Gitee.com 四、项目的具体实现
1、一些准备工作
首先我们新建一个springboot项目项目具体的创建流程我这里就不在赘述。 详见SpringBoot项目的创建 接下来我们就要数据库引入该项目。
数据库、数据表的创建 用户表的创建 文章表的创建 设置数据库和MyBatis的配置
配置数据库的连接信息 这里的很多内容是固定的
# 数据库连接配置
Spring:datasource:url: jdbc:mysql://localhost:3306/你要连接的数据库名?characterEncodingutf8useSSLfalseusername: 用户名password: 自己的密码driver-class-name: com.mysql.cj.jdbc.Driver #只要你数据库用的是mysql这个是固定的 配置MyBatis XML存放位置和命名规则 此时我们已经在通过maven将MySQL Driver和MyBatis Framework这两个包导入了进来此时启动项目项目依然能够正常运行说明我们数据库连接是正常的。 将前端项目引入到当前项目中
下面的前端的静态资源复制到我们resource/static目录下面 springboot项目-个人博客系统静态页面https://download.csdn.net/download/weixin_61061381/87459276 2、登录注册模块
实体类的创建
登录和注册不就是对用户表进行操作吗这个我们首先创建用户表对应的实体类 首先根据我们数据库的表在我们的程序中创建想对应的实体类——我们的MyBatis是ORM框架我们的程序对象与关系数据库数据之间有响应的映射关系 一个数据库中的数据表对应我们程序中的一个实体类数据表中的一行数据对应该实体类的一个实例化对象该数据表中的各个属性对应该实体类的成员变量属性对了还记我们springboot的扫描路径吗
只有在启动类的同级目录下springboot才会对该目录下的类进行扫描配合类注解存到spring容器中。 接下来我们就尝试给我们的用户表插入一条数据。 如上图所示我们从前端的login.html中获取到数据后经过控制层——》服务层——》数据持久层最后才作用到我们的数据库上。
废话不多说让我们跟着流程来走一遍吧 controller层 上图描述的是我们通过url直接调用了我们控制层的sayHi()方法并且把我们sayHi()方法返回的的结果展现在了浏览器上。 但是现在我们有前端了我们前端提交数据调用我们的后端controller层的登录方法然后把结果返回给前端不就行了吗用户是登录失败了还是成功了交由我们的前端来处理 前端后端交互
首先用户在前端页面输入了用户信息 然后前端紧接着就把用户输入的信息传递给后端提交到后端指定的接口上比如登录提交的就是/user/reg 后端接收到用户信息存到数据库中并返回注册的结果成功了还是失败了 前端接受到后端返回的结果后做进一步的处理 后端流程
还是先来看这张图 下面是根据上图流程构建的目录 controller层代码
package com.example.demo.controller;import com.example.demo.model.UserInfo;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;
/*** 而Spring Boot框架项目接口返回 JSON格式的数据比较简单* 在 Controller 类中使用RestController注解即可返回 JSON格式的数据。*/
RestController
RequestMapping(/user)
public class UserController {// 属性注入service服务层的userService类Autowiredpublic UserService userService;RequestMapping(/reg)public HashMapString, Object reg(String username, String password1, String password2) {HashMapString, Object result new HashMap();if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password1) || !StringUtils.hasLength(password2)) {result.put(status, -1);result.put(msg, 参数输入错误);result.put(data, );return result;}else {if (!password1.equals(password2)) {result.put(status, -1);result.put(msg, 前后密码不一致);result.put(data, );return result;}else {UserInfo userInfo new UserInfo();userInfo.setUsername(username);userInfo.setPassword(password1);int ret userService.reg(userInfo);if (ret ! 1) {result.put(status, -1);result.put(msg, 数据库添加出错);result.put(data, );return result;}else {result.put(status, 200);result.put(msg, 注册成功);result.put(data, ret);return result;}}}}
}在controller层中调用了service服务层的reg方法 service服务层又调用了持久层中的mapper接口 mapper接口的实现UserMapper.xml文件
?xml version1.0 encodingUTF-8?
!DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd
mapper namespacecom.example.demo.mapper.UserMapperinsert idreginsert into userinfo(username, password) values(#{userinfo.username}, #{userinfo.password});/insert
/mapper 到此关于注册整个前后端的流程就走完了下面我们来验证一下 但是当我们重复注册张三这个用户名 这个异常我们前端是不知道的我们不知道发生了什么是注册成功了还是失败了 在后端我们应该统一对异常进行处理并把具体的异常情况告诉前端 这就是我们下面要说的统一处理功能的实现 关于前后端参数的传递详见SpringMVC学习笔记获取参数传递参数——关于前后端传参交互的总结、from表单、Ajax数据提交_是小鱼儿哈的博客-CSDN博客 关于MyBatis实现数据库的增删改查详见第一个MyBatis程序_是小鱼儿哈的博客-CSDN博客 关于spring更简单的存取用户对象详见 spring更简单的对象存取 登录功能的实现和注册大同小异
后端流程 前后端交互的流程 下面我们通过浏览器验证一下我们的登录功能 一点补充
通过controller层的代码可以看到我们返回给前端的好像是hashmap这样肯定是不行的。
这个时候就用到了我们的RestController注解了 *RestController是Controller和ResponseBody两者的结合使用这个注解后该controller的所有方法都会返回json格式的数据* 因为ResponseBody的作用就是把返回的对象转换为json格式并把json数据写入response的body中前台收到response时就可以获取其body中的json数据了。
* 如果在整个controller类上方添加RestController其作用就相当于把该controller下的所有方法都加上ResponseBody使每个方法直接返回response对象 3、统一功能的处理
上面我们说了当程序出现了异常获取其他情况我们不统一处理把结果告诉前端我们其实是不知道发生了什么的。
统一异常处理
所以我们需要单独在工具层中我们的common包下面建一个统一异常处理的类 统一数据格式返回
一般在web项目中我们前后端都是通过json这种数据格式来交换数据格式——》我们后端需要给前端返回json格式的数据。
总之我们前后端用户交互的数据个数一般是统一的不会出现你一个接口用一种数据格式而那个接口又换了这样就会有很多问题不利于开发。
统一数据的优点 方便前端程序员更好的接受和解析后端数据接口返回的数据。降低前端程序员和后端程序员的沟通成本按照某个格式实现就可以了因为所有接口都是这样返回的。有利于项目统一数据的维护和修改。有利于后端技术部门的统一规范的标准制定不会出现稀奇古怪的返回内容。统一数据格式的返回有两种实现方式返回一个公共对象或者重写。
这里我们采用第二种重写不过他的灵活性有待提升
具体的我们可以使用ControllerAdviceResponseBodyAdvice的方式实现具体实现代码如下 但是正如我们上面所说的通过重写来进行统一数据格式的返回他的灵活性的确有待提高。你看我们上面只是处理了成功的情况但要是失败的情况呢——》并且即使失败也是分好几种情况呢 我们不如再创建一个工具类用来自定义返回hashmap数据再通过ResponseBody转成json格式 那么对应的我们的统一数据格式返回类就发生了变化
package com.example.demo.common;import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;import java.util.HashMap;/*** 统一数据格式返回灵活性有待提高* 通过统一数据格式的返回不管我们控制层的方法返回了什么类型的数据* 通过重写末尾都能把他转成hashmap格式的数据然后又通过ResponseBody注解将java对象转成了json对象。*/
ControllerAdvice
ResponseBody
public class ResponseAdvice implements ResponseBodyAdvice {Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true; // 这个值为true的时候才会对返回的数据进行重写}Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {// 在有了我们自定义数据返回后我们的这个统一数据格式返回类就像是一个托地的。// 因为controller层可以直接调用AjaxResult来返回hashmap(通过ResponseBody转成json)// 但如果controller没有调用AjaxResult直接返回了if (body instanceof HashMap) {return body; // 此时已经是hashmap格式了}if (body instanceof Integer){ // 当controller层中的方法直接返回int类型时候int num (int) body;if (num 0) {// 应对int类型错误返回(查询文章列表新增和删除博客可能会用到——》也可能用不到如果新增或查询失败我直接就在controller就返回了通过调用AjaxResult)// 新增、删除或查询失败非得在controller返回int值再通过这里返回json对象的话不灵活出错信息显示的不具体// 所以说这里我们只是以防万一我们还是选择再controller层直接返回json对象这样更信息具体更有怎针对性return AjaxResult.fail(抱歉本次操作失败请稍后再试); // 这里无法区分是新增失败还是删除失败// 这里我们本来返回的是一个hashmap格式的对象但加了ResponseBody把我们的java对象转成的了json格式}}if (body null) { // 比如查询操作直接返回查询到的UserInfo对象然后直接返回该对象// 这里我们本来返回的是一个hashmap格式的对象但加了ResponseBody把我们的java对象转成的了json格式return AjaxResult.fail(抱歉查询失败); // 这时对查询当前用户的特判}// 这里我们本来返回的是一个hashmap格式的对象但加了ResponseBody把我们的java对象转成的了json格式return AjaxResult.success(操作成功, body);// 前端是通过result中的status值来判断操作是否成功的这个类用来处理操作成功的情况为操作成功的情况兜底// 但这可能存在问题如果操作失败并且在controller层没有调用AjaxResult中的fail方法而是直接返回通过这个类来返回统一的数据格式就会出现问题——》在这个类我们都是按成功的处理的// 解决方案在该类中提前判断body(判断操作失败的情况---我们约定如果操作失败就返回负数在controller层调用AjaxResult的情况}
}那么与之对应的我们在controller层的类也就发生了改变
package com.example.demo.controller;import com.example.demo.common.AjaxResult;
import com.example.demo.model.UserInfo;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.jws.soap.SOAPBinding;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
/*** 而Spring Boot框架项目接口返回 JSON格式的数据比较简单* 在 Controller 类中使用RestController注解即可返回 JSON格式的数据。* RestController是Controller和ResponseBody两者的结合使用这个注解后该controller的所有方法都会返回json格式的数据* 因为ResponseBody的作用就是把返回的对象转换为json格式并把json数据写入response的body中前台收到response时就可以获取其body中的json数据了。* 如果在整个controller类上方添加RestController其作用就相当于把该controller下的所有方法都加上ResponseBody使每个方法直接返回response对象。*/
RestController
RequestMapping(/user)
public class UserController {Autowiredpublic UserService userService;RequestMapping(/reg)public Object reg(String username, String password1, String password2) {HashMapString, Object result new HashMap();if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password1) || !StringUtils.hasLength(password2)) {return AjaxResult.fail(你输入的参数有误请重新输入);}else {if (!password1.equals(password2)) {return AjaxResult.fail(前后密码不一致请重新输入);}else {UserInfo userInfo new UserInfo();userInfo.setUsername(username);userInfo.setPassword(password1);int ret userService.reg(userInfo);if (ret ! 1) {return AjaxResult.fail(数据库添加用户失败请稍后再试);}else {return AjaxResult.success(恭喜注册成功, ret);}}}}RequestMapping(/login)public Object login(String username, String password) {HashMapString, Object result new HashMap();if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password)) {return AjaxResult.fail(你输入的参数有误请重新输入);}else {// 需要在数据库中查询当前登录的用户是否存在UserInfo userInfo userService.selectByUsername(username);if (userInfo null || !password.equals(userInfo.getPassword())) {return AjaxResult.fail(你当前的用户名或密码错误请重新输入);}else {return AjaxResult.success(恭喜登录成功, );}}}
}统一用户的登录验证用户登录拦截器
spring拦截器 对于以上问题Spring中提供了具体的实现拦截器HandlerInterceptor,拦截器的实现分为以下两个步骤 1、创建自定义拦截器实现 HandlerInterceptor 接口的perHandle执行具体方法之前的预处理方法。 2、将自定义拦截器加入 WebMvcConfiger的 addInterceptors方法中。 创建用户登录拦截器 将该自定义拦截器放到系统的配置文件中
将自定义拦截器加入 WebMvcConfiger的 addInterceptors方法中 用浏览器测试一下是否真的拦截了 可以看到因为我们没有放行login.html登录页面直接显示不出来了。
我们改下拦截规则 然后你发现咦怎么还是不行。
当然不行呀你虽然运行了login.html通行但是login.html还用到了css/js/image图片呢这些东西你还没放行呢 过程中遇到的bug
一开始当我把自定义的用户登录拦截器放到了系统配置文件我欢欢喜喜的启动项目结果—— 加上类注解后问题就解决了。
关于统一功能的处理详见SpringBoot统一功能处理_是小鱼儿哈的博客-CSDN博客
4、博客列表页面的实现更新中...)
5、博客详情页面的实现
6、博客的修改和删除功能
7、博客列表分页功能的实现
8、随机加盐的实现