福建 专业网站建设公司,dw软件代码大全,h5游戏网站建设,做网站用什么语言开发提示#xff1a;文章写完后#xff0c;目录可以自动生成#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、项目介绍二、项目的整体框架 2.1 数据库模块 2.2 前端模块 2.3 后端模块三、项目图片展示四、项目的实现 4.1 准备工作 4.… 提示文章写完后目录可以自动生成如何生成可参考右边的帮助文档 文章目录 前言一、项目介绍二、项目的整体框架 2.1 数据库模块 2.2 前端模块 2.3 后端模块三、项目图片展示四、项目的实现 4.1 准备工作 4.1.1 数据库表的创建 4.1.2 配置数据库和MyBatis 4.1.3 引入前端项目 4.2 统一功能处理 4.2.1 统一异常功能处理 4.2.2 统一数据格式返回 4.2.3 统一用户登录验证 4.3 博客登录页的实现 4.3.1 实体类的创建 4.3.2 前后端交互 4.3.3 后端代码实现 4.4 博客列表页的实现 4.5 博客修改删除功能实现 4.6 博客分页功能实现总结 前言 一、项目介绍 项目名称博客笔记项目 主要操作的对象是文章和用户用户可在该系统上发表自己的博客查看自己或别人已经发表的文章 需要用到两张表userinfo(用户表、articleinfo文章表 需要实现的功能 登录注册 博客的分页列表功能 新增发表博客 修改、删除自己的博客 项目亮点 手动对用户密码实现随机加盐统一异常处理、拦截器用户登录持久化session内存分页功能 项目技术栈 SSMSpringBoot SpringMVC MyBatis MySQL jQuery 二、项目的整体框架
2.1 数据库模块 两张表用户表 文章表 2.2 前端模块 前端设计到7个页面 login.html登录页reg.html注册页blog_list.html总的博客列表页——》用到了blog_lmyblog_list.html个人博客列表页blog_content.html博客详情页blog_edit.html博客编辑页blog_update.html博客修改页 2.3 后端模块 后端模块 控制层controller包——》控制器服务层service包——》服务类持久层--数据访问层mapper类 mapper.xml——》mapper实体层model包——》实体类工具层config包util包——》统一异常处理、统一返回、随机加盐 三、项目具体展示 四、项目的实现
4.1 准备工作 首先我们新建一个springboot项目项目具体的创建流程我这里就不在赘述。 详细见链接SpringBoot的创建http://t.csdnimg.cn/XCd3R 引入需要的依赖pom.xml代码 ?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.7.8/versionrelativePath/ !-- lookup parent from repository --/parentgroupIdcom.example/groupIdartifactIddemo/artifactIdversion0.0.1-SNAPSHOT/versionnamedemo/namedescriptionDemo project for Spring Boot/descriptionpropertiesjava.version1.8/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactIdversion2.3.0/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-devtools/artifactIdscoperuntime/scopeoptionaltrue/optional/dependencydependencygroupIdcom.mysql/groupIdartifactIdmysql-connector-j/artifactIdscoperuntime/scope/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependencydependencygroupIdcn.hutool/groupIdartifactIdhutool-all/artifactIdversion5.8.10/version/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactIdconfigurationexcludesexcludegroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/exclude/excludes/configuration/plugin/pluginsfinalNamesxy_blog_system/finalName/build/project4.1.1 数据库表的创建 1.用户表的创建 2.文章表的创建 4.1.2 配置数据库和MyBatis 1.配置数据库的连接信息 注意 这里的很多内容是固定的 # 数据库连接配置
Spring:datasource:url: jdbc:mysql://localhost:3306/你要连接的数据库名?characterEncodingutf8useSSLfalseusername: 用户名password: 自己的密码driver-class-name: com.mysql.cj.jdbc.Driver #只要你数据库用的是mysql这个是固定的 2.配置MyBatis XML存放规则和命名规则 此时我们已经在通过maven将MySQL Driver和MyBatis Framework这两个包导入了进来此时启动项目项目依然能够正常运行说明我们数据库连接是正常的。 4.1.3 引入前端项目 下面的前端的静态资源复制到我们resource/static目录下面 4.2 统一功能处理
上面我们说了当程序出现了异常获取其他情况我们不统一处理。
4.2.1 统一异常功能处理 所以我们需要单独在工具层中我们的common包下面建一个统一异常处理的类 4.2.2 统一数据格式返回 一般在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(恭喜登录成功, );}}}
} 4.2.3 统一用户登录验证 spring拦截器 对于以上问题Spring中提供了具体的实现拦截器HandlerInterceptor, 拦截器的实现分为以下两个步骤 1、创建自定义拦截器实现 HandlerInterceptor 接口的perHandle执行具体方法之前的预处理方法。 2、将自定义拦截器加入 WebMvcConfiger的 addInterceptors方法中。 步骤1创建用户登录拦截器 步骤2 将该自定义拦截器放到系统的配置文件中 将自定义拦截器加入 WebMvcConfiger的 addInterceptors方法中 检验用浏览器测试一下是否真的拦截了 4.3 博客登录页的实现 4.3.1 实体类的创建 首先根据我们数据库的表在我们的程序中创建想对应的实体类——我们的MyBatis是ORM框架我们的程序对象与关系数据库数据之间有响应的映射关系 只有在启动类的同级目录下springboot才会对该目录下的类进行扫描配合类注解存到spring容器中。 4.3.2 前后端交互 1.首先用户在前端页面输入了用户信息 2.然后前端紧接着就把用户输入的信息传递给后端提交到后端指定的接口上比如登录提交的就是/user/reg 3.后端接收到用户信息存到数据库中并返回注册的结果成功了还是失败了 4.前端接受到后端返回的结果后做进一步的处理 4.3.3 后端代码实现 后端流程图 下面是根据上图流程构建的目录 在controller层中调用了service服务层的reg方法 service服务层又调用了持久层中的mapper接口 mapper接口的实现UserMapper.xml文件 注册前后端流程交互 4.4 博客列表页的实现 controller层代码 1.ArticleController代码实现 package com.example.demo.controller;import com.example.demo.config.AjaxResult;
import com.example.demo.model.ArticleInfo;
import com.example.demo.model.UserInfo;
import com.example.demo.service.ArticleService;
import com.example.demo.service.UserService;
import com.example.demo.util.ConstVariable;import lombok.SneakyThrows;
import org.apache.ibatis.annotations.ResultMap;
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.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.*;/*** 而Spring Boot框架项目接口返回 JSON格式的数据比较简单* 在 Controller 类中使用RestController注解即可返回 JSON格式的数据。*/
RestController
RequestMapping(/article)
public class ArticleController {Autowiredprivate ArticleService articleService;// 属性注入// 新增操作发表博客RequestMapping(/add)public Object add(HttpServletRequest request, String title, String content) {// todo 非空校验HttpSession session request.getSession(false);if (session null || session.getAttribute(ConstVariable.USER_SESSION_KEY) null) {return AjaxResult.fail(-1, 当前用户未登录博客发表失败);}UserInfo userInfo (UserInfo) session.getAttribute(ConstVariable.USER_SESSION_KEY);int uid userInfo.getId(); // 标记当前博客是那个用户发布的int rcount 1; // 表示当前博客的阅读量初始值新发表的博客阅读量1int state 1; // state表示当前博客状态 1 已发布 2》编辑中保存草稿// 新增博客ArticleInfo articleInfo new ArticleInfo();articleInfo.setTitle(title);articleInfo.setContent(content);articleInfo.setUid(uid);articleInfo.setRcount(rcount);articleInfo.setState(state);int result articleService.add(articleInfo);if (result 1) {return AjaxResult.success(博客发表成功, 1);}else {return AjaxResult.fail(-1, 数据库插入失败博客发表失败请稍后再试);}}// 查询指定用户id的所有博客SneakyThrowsRequestMapping(/get_mylist)public Object getMyBlogList(Integer uid, HttpServletResponse response) {
// if (uid null) {
// response.sendRedirect(/login.html); // 当前用户未登录
// }
// int uid Integer.parseInt(id);if (uid 0) {// response.sendRedirect(/lolgin.html); // 当前用户未登录return AjaxResult.fail(401, 当前用户未登录);}return AjaxResult.success(查找成功,articleService.getMyBlogList(uid));}// 查看指定博客id的博客详情--博客详情页此id为blogId形参名称要和前端传过来的参数一致RequestMapping(/get_by_blog_id)public Object selectByBlogId(int id) {if (id 0) {return AjaxResult.fail(-1, 参数出错无法找到指定博客的相关信息);}ArticleInfo articleInfo articleService.selectByBlogId(id);if (articleInfo null) {return AjaxResult.fail(-1, 数据库查询出错);}return AjaxResult.success(查找博客详情成功, articleInfo);}// 获取总的博客列表_无分页功能RequestMapping(/get_list)public ListArticleInfo getBlogList() {return articleService.getBlogList();}// 获取总的博客列表实现分页功能RequestMapping(/get_list_by_page)public Object getListByPage(Integer pindex, Integer psize) {HashMapString, Object data new HashMap();// 登录进去后第一次初始化页面时候url list.html即pindex是空的username等也是空的if (pindex null || pindex 1) {pindex 1;}if (psize null || psize 0) {psize 2;}// 上面这些特殊情况的处理很重要就是应对url list.html这种情况如果没有特判会出错查询不到数据// 我们前后端都对这些特殊情况做了处理——不多余双重保障你进入公司后前端可不是你写的所以我们就要把我们负责的后端写的扎实不管前端怎么传我后端都能应对int offset (pindex - 1) * psize;ListArticleInfo list articleService.getListByPage(psize, offset);// 得出用户名为username,地址为address,邮箱为email的所有用户个数// getPageCount函数————》得到总的博客条数int totalCount articleService.getPageCount();data.put(list, list);data.put(count, totalCount);return AjaxResult.success(分页功能的实现, data);}// 删除指定博客id的博客SneakyThrowsRequestMapping(/del)public Object del(HttpServletRequest request, int id, HttpServletResponse response) {ArticleInfo articleInfo articleService.selectByBlogId(id);HttpSession session request.getSession(false);if (session null || session.getAttribute(ConstVariable.USER_SESSION_KEY) null) {// response.sendRedirect(/login.html);return AjaxResult.fail(401, 当前用户未登录);}// 这篇博客的作者uid和当前登录的用户id相同才有权限删除UserInfo userInfo (UserInfo) session.getAttribute(ConstVariable.USER_SESSION_KEY);if (articleInfo.getUid() ! userInfo.getId()) {
// response.sendRedirect(/blog_list.html);return AjaxResult.fail(-1, 你不是该篇博客的作者你无权限进行删除操作);}if (id 0) {return AjaxResult.fail(-1, 找不到要删除的博客删除失败);}int result articleService.del(id);if (result 0) {return AjaxResult.fail(-1, 数据库删除操作失败);}// 获取该篇博客的作者idQueueInteger queue new LinkedList();ArrayListInteger list new ArrayList();ArrayListArrayListInteger lists new ArrayList();// response.sendRedirect(/blog_list.html);return AjaxResult.success(删除博客成功, result);}/*** 修改指定id的博客内容或标题*/RequestMapping(/update)public Object update(HttpServletRequest request, int id, String title, String content) {if (id 0) return AjaxResult.fail(-1, 你指定的博客id有误稍后再试);ArticleInfo articleInfo articleService.selectByBlogId(id);HttpSession session request.getSession(false);if (session null || session.getAttribute(ConstVariable.USER_SESSION_KEY) null) {// response.sendRedirect(/login.html);return AjaxResult.fail(401, 当前用户未登录);}// 这篇博客的作者uid和当前登录的用户id相同才有权限删除UserInfo userInfo (UserInfo) session.getAttribute(ConstVariable.USER_SESSION_KEY);if (articleInfo.getUid() ! userInfo.getId()) {
// response.sendRedirect(/blog_list.html);return AjaxResult.fail(-1, 你不是该篇博客的作者你无权限进行修改操作);}else {int ret articleService.update(id, title, content);if (ret 0) {return AjaxResult.fail(-1, 数据库更新操作失败);}else {return AjaxResult.success(更新博客成功, ret);}}}}2.UserController代码实现 package com.example.demo.controller;import com.example.demo.config.AjaxResult;
import com.example.demo.model.UserInfo;
import com.example.demo.service.UserService;
import com.example.demo.util.ConstVariable;
import com.example.demo.util.PasswordUtil;import lombok.SneakyThrows;
import org.apache.ibatis.annotations.ResultMap;
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.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;RestController
RequestMapping(/user)
public class UserController {Autowiredprivate UserService userService;/*** 用户注册* param username* param password1* param password2* return*/RequestMapping(/reg)public Object reg(String username, String password1, String password2) {if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password1) || !StringUtils.hasLength(password2)) {return AjaxResult.fail(-1, 参数输入错误);}else {if (!password1.equals(password2)) {return AjaxResult.fail(-1, 前后密码不一致);}else {int result userService.reg(username, PasswordUtil.encrypt(password1));if (result ! 1) {return AjaxResult.fail(-1, 数据库添加出错);}return AjaxResult.success(注册成功, 1);}}}/*** 用户登录* param request* param username* param password* return*/RequestMapping(/login)public Object login(HttpServletRequest request, String username, String password) {if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password)) {return AjaxResult.fail(-1, 参数输入错误,登录失败);}UserInfo userInfo userService.selectByUsername(username);// 随机加盐算法未加密的密码用同样的加密算法和数据库中的加密算法进行比较if (userInfo null || ! PasswordUtil.decrypt(password, userInfo.getPassword()) || userInfo.getId() 0) {return AjaxResult.fail(-1, 账号或密码错误登录失败);}// 如果程序走到这里说明登陆成功了// 每次登录成功都要对数据库中的密码进行重新生成,这样才符合随机加密// userService.passwordRefresh()HttpSession session request.getSession(); // 获取session如果没有就创建一个session.setAttribute(ConstVariable.USER_SESSION_KEY, userInfo);return AjaxResult.success(登录成功, 1);}/*** 获取当前登录的用户名*/RequestMapping(/get_user)public Object getUser(HttpServletRequest request) {HttpSession session request.getSession(false);if (session null) {return AjaxResult.fail(401, 当前用户未登录);}UserInfo userInfo (UserInfo) session.getAttribute(ConstVariable.USER_SESSION_KEY);if (userInfo null) {return AjaxResult.fail(401, 当前用户未登录);}return userInfo; // 这里我们可以直接用AjaxResult自定义统一格式返回也可以传统的统一格式返回}/*** 退出登录* param request* param response*/SneakyThrowsRequestMapping(/logout)public Object logout(HttpServletRequest request, HttpServletResponse response) {HttpSession session request.getSession(false);if (session null || session.getAttribute(ConstVariable.USER_SESSION_KEY) null) {// response.sendRedirect(/login.html); // 当前用户未登录return AjaxResult.fail(401, 当前用户未登录);}session.setAttribute(ConstVariable.USER_SESSION_KEY, null);//response.sendRedirect(/login.html);return AjaxResult.success(当前状态正常可以正常退出, true);}/*** 通过个人id(uid)查询个人详细信息* param authorId* return*/RequestMapping(/get_detail_by_uid)public Object selectByUid(Integer authorId) {int uid authorId;if (uid 0) {return AjaxResult.fail(-1, uid《0查询出错);}UserInfo userInfo userService.selectByUid(uid);if (userInfo null) {return AjaxResult.fail(-1, 在数据库中查询不到指定用户id的详细信息请稍后再试);}return AjaxResult.success(通过uid查询个人详细信息成功, userInfo);}
}在controller层中调用了service服务层的reg方法 service服务层又调用了持久层中的mapper接口 4.5 博客修改删除功能实现 mapper层代码 1.Articlemapper package com.example.demo.mapper;import com.example.demo.model.ArticleInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;import java.util.List;Mapper
public interface ArticleMapper {// 发布新文章public int add(Param(articleinfo)ArticleInfo articleinfo);// 查询指定博客id的博客详情--》用于博客详情页public ArticleInfo selectByBlogId(Param(blogId) int blogId);// 查询个人的博客列表——》个人博客详情页public ListArticleInfo getMyBlogList(Param(uid) int uid);// 查询总的博客列表无分页功能public ListArticleInfo getBlogList();// 删除指定博客id的博客public int del(Param(id) int id);// 得到当前的博客总数目public int getPageCount();// 查询总的博客列表分页功能的实现_注意limit和offset的位置相对位置参数的相对位置不要弄反——》查询数据库会出错public ListArticleInfo getListByPage(Param(limit) int psize, Param(offset) int offset);// psize对应limit--》表示每页显示的记录条数。pindex对应offset——》表示当前查看的是第几页的数据// 修改指定博客id的博客title和content-----------注意形参的顺序public int update(Param(title) String title, Param(content) String content, Param(id) int id);}2.Usermapper代码实现 package com.example.demo.mapper;import com.example.demo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;Mapper
public interface UserMapper {// 用户注册public int reg(Param(username) String username, Param(password) String password);// 通过名称查询用户--用于登录的验证public UserInfo selectByUsername(Param(username) String username);// 通过个人id(uid)查询个人详细信息public UserInfo selectByUid(Param(uid) int uid);
}1.AjaxResult代码 用户登录拦截器自定义拦截器添加到系统的配置文件中。 package com.example.demo.config;import org.springframework.stereotype.Controller;import java.util.HashMap;/*** 自定义返回数据我们通过AjaxResult类返回的都是hashmap格式的对象* 之后还有通过ResponseBody将java对象转成json格式的数据*/
public class AjaxResult {/*** 操作成功无msg* param data* return*/public static Object success(Object data) {HashMapString, Object result new HashMap();result.put(state, 200);result.put(msg, );result.put(data, data);return result;}/*** 操作成功有msg* param msg* param data* return*/public static Object success(Object msg, Object data) {HashMapString, Object result new HashMap();result.put(state, 200);result.put(msg, msg);result.put(data, data);return result;}/*** 操作失败无data* param state* param msg* return*/public static Object fail(int state, Object msg) {HashMapString, Object result new HashMap();result.put(state, state);result.put(msg, msg);result.put(data, );return result;}/*** 操作失败有data)* param state* param msg* param data* return*/public static Object fail(int state, Object msg, Object data) {HashMapString, Object result new HashMap();result.put(state, state);result.put(msg, msg);result.put(data, data);return result;}
}2.Logininterception代码 用户登录拦截器查看当前用户是否登录 package com.example.demo.config;import com.example.demo.util.ConstVariable;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.HashSet;/*** 用户登录拦截器查看当前用户是否登录*/
Component
public class LoginInterception implements HandlerInterceptor {Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {HttpSession session request.getSession(false);if (session null || session.getAttribute(ConstVariable.USER_SESSION_KEY) null) {// 当前用户未登录进行拦截---跳转到登录页面---后端我们只用给前端返回状态和数据我们后端不用管页面怎么跳转工作是前端的事情// response.sendRedirect(/login.html);// 401表示未登录没有权限403不是因为没有登录而没有权限而是该用户没有权限管理员和普通用户的区别response.setStatus(401);response.sendError(401, 当前用户为登录没有权限访问该接口);return false;}return true;}
}3.ResponseAdvice代码 数据格式同样返回(这个是兜底的即使controller层返回的是int或string类型的数据也可以转换成json格式 注意只能兜底int类的返回可以应对操作成功和失败两种情况 如果是String或其他格式的返回可以应对操作成功的情况但无法应对操作失败的情况要继续对body进行特判 package com.example.demo.config;import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
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.beans.PropertyEditorSupport;
import java.util.HashMap;/*** 数据格式同样返回(这个是兜底的即使controller层返回的是int或string类型的数据也可以转换成json格式* 注意只能兜底int类的返回可以应对操作成功和失败两种情况* 如果是String或其他格式的返回可以应对操作成功的情况但无法应对操作失败的情况要继续对body进行特判** 这里我们只是以防万一我们尽量还是选择再controller层直接返回json对象这样更信息具体更有怎针对性*/
ControllerAdvice // 统一功能处理需要加这个注解
ResponseBody
// ResponseBody的作用就是把返回的对象转换为json格式并把json数据写入response的body中前台收到response时就可以获取其body中的json数据了。
public class ResponseAdvice implements ResponseBodyAdvice {Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true; // 返回true才会继续执行下面的代码}SneakyThrowsOverridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {if (body instanceof HashMap) {return body; // 此时已经是hashmap格式了}
// HashMapString, Object result new HashMap();
// result.put(state, 200);
// result.put(msg, );
// result.put(data, body);if (body instanceof Integer){int num (int) body;if (num 0) {// 应对int类型错误返回(查询文章列表新增和删除博客可能会用到——》也可能用不到如果新增或查询失败我直接就在controller就返回了通过调用AjaxResult)// 新增、删除或查询失败非得在controller返回int值再通过这里返回json对象的话不灵活出错信息显示的不具体// 所以说这里我们只是以防万一我们还是选择再controller层直接返回json对象这样更信息具体更有怎针对性return AjaxResult.fail(-1,抱歉本次操作失败请稍后再试); // 这里无法区分是新增失败还是删除失败// 这里我们本来返回的是一个hashmap格式的对象但加了ResponseBody把我们的java对象转成的了json格式}}if (body null) { // 应对String类型错误返回// 这里我们本来返回的是一个hashmap格式的对象但加了ResponseBody把我们的java对象转成的了json格式return AjaxResult.fail(-1,抱歉查询失败); // 这时对查询当前用户的特判}if (body instanceof String) { // 以String类型正确返回ObjectMapper objectMapper new ObjectMapper();return objectMapper.writeValueAsString(body); // 用jackson中的工具类返回(没弄明白——》直接返回String吧不序列化了详见https://zhuanlan.zhihu.com/p/196372502}// 这里我们本来返回的是一个hashmap格式的对象但加了ResponseBody把我们的java对象转成的了json格式return AjaxResult.success(body);// 前端是通过result中的state值来判断操作是否成功的这个类用来处理操作成功的情况为操作成功的情况兜底// 但这可能存在问题如果操作失败并且在controller层没有调用AjaxResult中的fail方法而是直接返回通过这个类来返回统一的数据格式就会出现问题——》在这个类我们都是按成功的处理的// 解决方案在该类中提前判断body(判断操作失败的情况---我们约定如果操作失败就返回负数在controller层调用AjaxResult的情况}
}4.6 博客分页功能实现 1.ExcptionAdvice代码 统一异常处理 ResponseBody的作用就是把返回的对象转换为json格式并把json数据写入response的body中前台收到response时就可以获取其body中的json数据了 package com.example.demo.config;import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;import java.util.HashMap;/*** 统一异常处理*/
ControllerAdvice
ResponseBody
// ResponseBody的作用就是把返回的对象转换为json格式并把json数据写入response的body中前台收到response时就可以获取其body中的json数据了。
public class ExceptionAdvice {ExceptionHandler(Exception.class)public Object exceptionAdvice(Exception e) {// 这里我们本来返回的是一个hashmap格式的对象但加了ResponseBody把我们的java对象转成的了json格式return AjaxResult.fail(-1, e.getMessage());}// 你这里的统一异常处理并不完整}2.ApplicationConfig代码 package com.example.demo.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;// 系统配置文件类
Configuration // 该配置文件在项目启动时配置
public class ApplicationConfig implements WebMvcConfigurer {Autowiredprivate LoginInterception loginInterception; // 用户登录拦截器// 自定义拦截器添加到系统的配置文件中Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterception).addPathPatterns(/**) // 设置拦截规则
// .excludePathPatterns(/login.html)// 下面这些指定的url不会检查是否登录——进行拦截
// .excludePathPatterns(/reg.html).excludePathPatterns(/**/*.html).excludePathPatterns(/user/login).excludePathPatterns(/user/reg)// 总的博客的列表和博客详情我们需要开放权限即使用户未登录也可以查看.excludePathPatterns(/article/get_list_by_page) // 放行总博客列表.excludePathPatterns(/article/get_by_blog_id) // 放行博客详情页面.excludePathPatterns(/user/get_detail_by_uid)//.excludePathPatterns(/css/**)---和下一行的作用是一样的//.excludePathPatterns(/**/*.css).excludePathPatterns(/css/**).excludePathPatterns(/js/**).excludePathPatterns(/editor.md/**).excludePathPatterns(/img/**); // 直接img目录下的所有都放行}
}总结