项目实战 — 博客系统③ {功能实现}

目录

 一、编写注册功能

🍅 1、使用ajax构造请求(前端)

🍅 2、统一处理

        🎄 统一对象处理

        🎄 保底统一返回处理 

        🎄 统一异常处理

 🍅 3、处理请求

二、编写登录功能

 🍅 1、使用ajax构造请求

🍅 2、处理请求

        🎄 创建实体类

        🎄 添加接口方法

         🎄 service层

        🎄 controller:处理请求并返回

三、编写博客列表页面

 🍅 1、SessionUtils

 🍅 2、处理请求

🍅 3、使用ajax构造请求

三、编写注销功能

🍅 1、使用ajax获取请求

🍅 2、处理请求

四、编写删除文章功能

🍅 1、使用ajax构造请求

🍅 2、处理请求

🎄 mapper层:接口方法

🎄 service层

🎄 controller层:处理请求

五、编写文章添加功能

🍅 1、使用ajax构造请求

🍅 2、处理请求

 🎄mapper层:添加接口方法

 🎄service层:返回受影响行数

🎄 controller:处理添加文章的请求

六、修改功能:查询到修改的文章

🍅 1、通过ajax构造请求

🍅 2、处理请求

🎄Mapper层:添加接口

🎄service层

🎄controller层

七、修改功能:修改查询到的文章

🍅 1、通过ajax构造请求           

🍅 2、处理请求

🎄 mapper层

🎄 service层

🎄 controller层     

八、文章详情

🍅 1、前端页面编写

🎄 给定id值

 🎄 使用ajax构造请求

🍅 2、处理请求

🎄 mapper层

🎄 service层

🎄 controller层 

九、阅读量设置

🍅 处理请求

🎄 mapper层

🎄 service层

🎄 controller层 

 十、分页处理

🍅 1、前端处理

🍅 2、后端处理

🎄 mapper层

🎄 service层

🎄 controller层 

十一、密码加盐

🍅 1、定义加密规则

🍅 2、修改UserController代码


前置知识:

前后端交互的关键:使用AJAX(异步局部提交)

写法:

        1、原生写法(兼容性差)

        2、使用框架,jQuery ajax(简单 / 通用性浩)

语法:

        jQuery.ajax({url:"接口地址",           //提高的接口地址type:"GET",               //请求的类型data:{                         //传递的数据"username":"张三","password":"123"},success:function(res){        //相应的结果是什么//后端返回数据后的业务处理代码}});

 一、编写注册功能

🍅 1、使用ajax构造请求(前端)

在前端页面的<head></head>添加jquery

<script src="js/jquery.min.js"></script>

添加事件:点击提交按钮,触发mysub()

<div class="row"><button id="submit" onclick="mysub()">提交</button>
</div>

在<script></script>中提交用户注册信息

主要有这几步:

        (1)参数效验(获取到数据|非空效验)

        (2)将数据提交给后端

        (3)将后端返回的结果给用户

username.focus():指将光标返回

trim():去空格操作(校验到全是空格)

<script>//  提交用户注册信息function mysub(){// 参数校验var username = jQuery("#username");var password = jQuery("#password");var password2 = jQuery("#password2");if(username.val().trim()==""){alert("请先输入用户名!");username.focus();return false;}if(password.val().trim()==""){alert("请先输入密码!");password.focus();return false;}if(password2.val().trim()==""){alert("请先输入确认密码!");password2.focus();return false;}// 效验两次输入的密码是否一致if(password.val()!=password2.val()){alert("两次密码不一致,请先检查!");return false;}//     提交数据给后端jQuery.ajax({url:"/user/reg",// 查询使用get,非查询使用posttype:"POST",data:{"username":username.val().trim(),"password":password.val().trim()},success:function (res){//     返回结果给用户if (res.code==200 && res.data==1){alert("注册成功!")location.href = "login.html";}else {alert("注册失败!" + res.msg);}}});}</script>
</body>

🍅 2、统一处理

        🎄 统一对象处理

 在common包中,编写ResultAjax,表示前后端交互的统一对象,统一处理

@Data
public class ResultAjax {private int code;   //状态码private String msg; //状态码的描述信息private Object data;public static ResultAjax success(Object data){ResultAjax result = new ResultAjax();result.setCode(200);result.setMsg("");result.setData(data);return result;}public static ResultAjax success(int code,String msg,Object data){ResultAjax result = new ResultAjax();result.setCode(code);result.setMsg(msg);result.setData(data);return result;}public static ResultAjax fail(int code,String msg){ResultAjax result = new ResultAjax();result.setCode(code);result.setMsg(msg);result.setData(null);return result;}public static ResultAjax fail(int code,String msg,Object data){ResultAjax result = new ResultAjax();result.setCode(code);result.setMsg(msg);result.setData(data);return result;}
}

        🎄 保底统一返回处理 

        在common中创建类

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {@Autowiredprivate ObjectMapper objectMapper;@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {if (body instanceof ResultAjax){return body;}if (body instanceof String){ResultAjax resultAjax = ResultAjax.success(body);try {return objectMapper.writeValueAsString(resultAjax);} catch (JsonProcessingException e) {e.printStackTrace();}}return ResultAjax.success(body);}
}

        🎄 统一异常处理

/*
* 统一异常处理
* */
@RestControllerAdvice
public class ExceptionAdvice {@ExceptionHandler(Exception.class)public ResultAjax doException(Exception e){return ResultAjax.fail(-1,e.getMessage());}
}

 🍅 3、处理请求

 编写Mapper层,将拿到的数据进行插入

@Mapper
public interface UserMapper {@Insert("insert into userinfo(username,password) values (#{username},#{password})")int reg(Userinfo userinfo);
}

然后在Service层中使用@Autowired将userMapper注入

@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public int reg(Userinfo userinfo){return userMapper.reg(userinfo);}
}

 在UserController中使用Userinfo对象接收请求信息

        (1)校验参数

        (2)请求 service 进行添加操作

        (3)将执行的结果返回给前端

@RestController
@RequestMapping("/user")
public class UserController {@AutowiredUserService userService;@RequestMapping("/reg")public ResultAjax reg(Userinfo userinfo){if (userinfo == null || !StringUtils.hasLength(userinfo.getUsername())|| !StringUtils.hasLength(userinfo.getPassword())){return ResultAjax.fail(-1,"非法参数");}int result = userService.reg(userinfo);return ResultAjax.success(result);}

检验该功能是否实现

 查看数据库是否插入张三的信息:

二、编写登录功能

 🍅 1、使用ajax构造请求

 在前端页面的<head></head>添加jquery

<script src="js/jquery.min.js"></script>

添加事件:点击提交按钮,触发mysub()

<div class="row"><button id="submit" onclick="doLogin()">提交</button>
</div>

        (1)校验参数

        (2)将数据提交给后端

        (3)将结果展示给前端

<script>function doLogin(){// 参数校验var username = jQuery("#username");var password = jQuery("#password");if(username.val().trim()==""){alert("请先输入用户名!");username.focus();return false;}if(password.val().trim()==""){alert("请先输入密码!");password.focus();return false;}//     将数据提交给后端jQuery.ajax({url:"/user/login",type:"GET",data:{"username":username.val(),"password":password.val()},success:function(res){//     将结果展示给用户if (res.code==200 && res.data==1){alert("登录成功!");location.href="myblog_list.html";}else {alert("登录失败!" + res.msg);}}});}
</script>

🍅 2、处理请求

        🎄 创建实体类

首先,再创建一个扩展Userinfo的实体类,UserinfoVO

/*
* userinfo扩展类
* */
@Data
public class UserinfoVO extends Userinfo {private String checkCode;
}

        🎄 添加接口方法

在UserMapper中添加以下方法:

@Select("select * from userinfo where username = #{username} order by id desc")Userinfo getUserByName(@Param("username")String username);

         🎄 service层

 public Userinfo getUserByName(String username){return userMapper.getUserByName(username);}

        🎄 controller:处理请求并返回

首先创建一个公共类(common包中):AppVariable

设置一个用户的session key

/*
* 全局变量
* */
public class AppVariable {public static final String SESSION_USERINFO_KEY = "SESSION_USERINFO";
}

        (1)参数校验

        (2)根据用户名查询对象

        (3)适用对象中的密码和用户输入的密码进行比较

          登录验证思路:根据用户名查询对象,如果查询到对象,则用查询到的对象和传递过              来的密码对比。如果相同,则说明登陆成功,反之则不能。   

        (4)比较成功之后,将对象存储到session中

        (5)将结果返回给用户

 @RequestMapping("/login")public ResultAjax login(UserinfoVO userinfoVO, HttpServletRequest request){//参数校验if (userinfoVO == null || !StringUtils.hasLength(userinfoVO.getUsername()) ||!StringUtils.hasLength(userinfoVO.getPassword())){
//            是非法登录return ResultAjax.fail(-1,"参数有误!");}//根据用户查询对象Userinfo userinfo = userService.getUserByName(userinfoVO.getUsername());if (userinfo == null || userinfo.getId() == 0){return ResultAjax.fail(-2,"用户名或密码错误!");}//使用对象中的密码和用户输入的密码进行比较if (!userinfoVO.getPassword().equals(userinfo.getPassword())){
//            密码错误return ResultAjax.fail(-2,"用户名或密码错误!");}//比较成功,将对象存储到session中HttpSession session = request.getSession();session.setAttribute(AppVariable.SESSION_USERINFO_KEY,userinfo);//将结果返回给用户return ResultAjax.success(1);}

三、编写博客列表页面

 🍅 1、SessionUtils

由于要拿到用户的信息,也就是拿到用户对象,比如修改和删除博客等功能(都是需要拿到用户),所以得到用户对象就属于一个高频事件。

所以就创建一个类,可以得到用户对象。

/*
* session工具类
* */
public class SessionUtils {
//    得到登录用户public static Userinfo getUser(HttpServletRequest request){
//        false代表有session就创建session,没有就创建HttpSession session = request.getSession(false);if (session != null && session.getAttribute(AppVariable.SESSION_USERINFO_KEY) != null){
//            登录状态return (Userinfo) session.getAttribute(AppVariable.SESSION_USERINFO_KEY);}return null;}
}

 🍅 2、处理请求

🎄 添加接口方法(mapper)

@Mapper
public interface ArticleMapper {@Select("select * from articleinfo where uid=#{uid}")List<ArticleMapper> getListByUid(@Param("uid")int uid);
}

🎄 service层

对象注入

@Service
public class ArticleService {@Autowiredprivate ArticleMapper articleMapper;public List<ArticleMapper> getListByUid(int uid){return articleMapper.getListByUid(uid);}
}

🎄controller处理请求并返回响应

使用并行的方式处理文章正文(_DESC_LENGTH是简介)

@RestController
@RequestMapping("art")
public class ArticleController {@Autowiredpublic ArticleService articleService;private static final int _DESC_LENGTH = 120;@RequestMapping("/mylist")public ResultAjax myList(HttpServletRequest request){
//        得到登录用户Userinfo userinfo = SessionUtils.getUser(request);if (userinfo == null){return ResultAjax.fail(-1,"请先登录");}
//      根据用户id查询用户发表的文章List<Articleinfo> list = articleService.getListByUid(userinfo.getId());
//        处理list -> 将文章正文变成简介if (list != null && list.size() > 0){
//            并行处理list集合list.stream().parallel().forEach((art)->{if (art.getContent().length() > _DESC_LENGTH){art.setContent(art.getContent().substring(0,_DESC_LENGTH));}});}
//        返回前端return ResultAjax.success(list);}
}

🍅 3、使用ajax构造请求

在前端页面的<head></head>添加jquery

<script src="js/jquery.min.js"></script>

添加一个id,包含了文章列表的div

       <div id="artListDiv" class="container-right">
 <script>// 初始化方法function init(){jQuery.ajax({url:"/art/mylist",type:"GET",data:{},success:function(res){if(res.code==200){// 请求成功var createHtml = "";var artList = res.data;if(artList==null || artList.length==0){// 未发表文章createHtml += "<h3 style='margin-left:20px;margin-top:20px'>暂无文章,请先"+"<a href='blog_add.html'>添加</a>!</h3>";}else{for(var i=0;i<artList.length;i++){var art = artList[i];createHtml += '<div class="blog">';createHtml += '<div class="title">'+art.title+'</div>';createHtml += '<div class="date">'+art.createtime+'</div>';createHtml += '<div class="desc">';createHtml += art.content;createHtml += '</div>';createHtml += ' <a href="blog_content.html?aid='+art.id + '" class="detail">查看全文 &gt;&gt;</a>&nbsp;&nbsp;';createHtml += '<a href="blog_edit.html?aid='+art.id + '" class="detail">修改 &gt;&gt;</a>&nbsp;&nbsp;';createHtml += ' <a href="javascript:del('+art.id+')" class="detail">删除 &gt;&gt;</a>';createHtml += '</div>';}}jQuery("#artListDiv").html(createHtml);}else{alert("抱歉:操作失败!"+res.msg);}}});}init();</script>
</body>

三、编写注销功能

🍅 1、使用ajax获取请求

由于注销功能,在很多页面都需要用到,所以这里就给一个公共的js

function logout(){if (confirm("是否确定注销?")){// 1、在后端删除session信息jQuery.ajax({url:"/user/logout",type:"POST",data:{},success:function (res){}});// 2、跳转到登录页location.href = "login.html"}
}

 进入到myblog_list.html中:

<script src="js/logout.js"></script>
<a href="javascript:logout()">注销</a>

🍅 2、处理请求

//注销@RequestMapping("/logout")public ResultAjax logout(HttpServletRequest request){HttpSession session = request.getSession(false);if (session!=null &&session.getAttribute(AppVariable.SESSION_USERINFO_KEY)!=null){session.removeAttribute(AppVariable.SESSION_USERINFO_KEY);}return ResultAjax.success(1);}

四、编写删除文章功能

🍅 1、使用ajax构造请求

在myblog_list.html中添加对应的js代码

主要是根据id删除文章:

        1、校验参数

        2、将数据返回给后端进行删除操作

        2、将结果展示给用户

 //     删除文章操作(根据id删除)function del(aid){//     参数校验if(aid=="" || aid<=0){alert("参数错误");return false;}//     将数据返回给后端进行删除操作jQuery.ajax({url:"/art/del",type:"POST",data:{"aid":aid},success:function (res){//     将结果展示给用户if (res.code==200 && res.data==1){alert("恭喜:删除成功!");//     刷新页面location.href = location.href;}else {//     删除失败alert("抱歉:操作失败!"+res.msg);}}});}

🍅 2、处理请求

🎄 mapper层:接口方法

在ArticleMapper中添加接口方法

@Delete("delete from articleinfo where id=#{aid} and uid=#{uid}")
int del(@Param("aid")Integer aid,int uid);

🎄 service层

public int del(Integer aid,int uid){return articleMapper.del(aid,uid);}

🎄 controller层:处理请求

主要有以下几步:

        1、参数校验

        2、得到当前登录的用户

        3、判断文章的归属人并且进行删除操作

        4、将结果返回给前端

//    删除文章@RequestMapping("/del")public ResultAjax del(Integer aid,HttpServletRequest request){if (aid==null || aid<=0){return ResultAjax.fail(-1,"参数错误!");}Userinfo userinfo = SessionUtils.getUser(request);if (userinfo == null){return ResultAjax.fail(-1,"请先登录!");}int result = articleService.del(aid,userinfo.getId());return ResultAjax.success(result);}

五、编写文章添加功能

🍅 1、使用ajax构造请求

        (1)非空校验

        (2)将用户提交的数据传递给后端

        (3)将后端返回的结果展示给用户

进入到blog_add.html中,添加如下代码

 function mysub(){var title = jQuery("#title");if (title.val.trim()==""){alert("请先输入标题!");title.focus();return false;}if (editor.getValue()==""){alert("请先输入正文!");return false;}jQuery.ajax({url:"/art/add",type:"POST",data:{"title":title.val(),"content":editor.getValue()},success:function (res){// 文章添加成功if (res.code==200 && res.data==1){if (confirm("恭喜:添加成功!是否继续添加文章?")){location.href=location.href;}else{location.href="myblog_list.html"}}else {//文章添加失败alert("抱歉:操作失败!"+res.msg);}}});}

🍅 2、处理请求

 🎄mapper层:添加接口方法

@Insert("insert into articleinfo(title,content,uid) values(#{title},#{content},#{uid})")int add(Articleinfo articleinfo);

 🎄service层:返回受影响行数

public int add(Articleinfo articleinfo){return articleMapper.add(articleinfo);}

🎄 controller:处理添加文章的请求

主要分为以下几步:

        (1)校验参数

        (2)组装数据

        (3)将数据入库

        (4)将结果返回给前端

@RequestMapping("/add")public ResultAjax add(Articleinfo articleinfo,HttpServletRequest request){if (articleinfo==null || !StringUtils.hasLength(articleinfo.getTitle())|| !StringUtils.hasLength(articleinfo.getContent())){return ResultAjax.fail(-1,"非法参数!");}Userinfo userinfo = SessionUtils.getUser(request);if (userinfo == null){return ResultAjax.fail(-2,"请先登录");}articleinfo.setUid(userinfo.getId());int result = articleService.add(articleinfo);return ResultAjax.success(result);}

六、修改功能:查询到修改的文章

🍅 1、通过ajax构造请求

(1)获取url中的参数:

(例如)localhost:8080/blog_edit.html?aid=2&uid=1

        a、通过location.search获取“?”后面的参数

        b、去除“?”

        c、根据“&”将参数分割成多个数组

        d、循环对比key,并返回查询value

创建一个公共的js:

// 根据key获取到对应的url中对应的value
function getParamValue(key){var params = location.search;if (params.indexOf("?")>=0){params=params.substring(1);var paramArray=params.split("&");if (paramArray.length>=1){for (var i = 0; i < paramArray.length; i++) {var item=paramArray[i].split("=");if (item[0]==key[1]){return item;}}}}return null;
}

(2)校验 aid

(3)查询文章详情

(4)将文章的详情信息展示到页面

首先在head中添加得到参数的方法

    <script src="js/urlutils.js"></script>

在blog_edit.html中的<script></script>中添加代码

        var aid=getParamValue("aid");function init(){if (aid==null || aid<=0){alert("非法参数")return false;}jQuert.ajax({url:"/art/getdetail",type:"GET",data:{"aid":aid},success:function(res){if (res.code==200 && res.data!=null && res.data.id>0){jQuery("#title").val(res.data.title);initEdit(res.data.content);}else {alert("抱歉,查询失败!"+res.msg);}}});}init();

🍅 2、处理请求

🎄Mapper层:添加接口

进入到ArticleMapper中

@Select("select  * from aeticleinfo where id=#{aid} and uid=#{uid}")Articleinfo getArticleByIdAndUid(@Param("aid")int aid,@Param("uid")int uid);

🎄service层

 public Articleinfo getArticleByIdAndUid(int aid,int uid){return ArticleMapper.getArticleByIdAndUid(aid,uid);}

🎄controller层

(1)校验参数

(2)得到当前登录用户id

(3)查询文章并且校验权限

@RequestMapping("/update_init")public ResultAjax updateInit(Integer aid,HttpServletRequest request){if (aid==null || aid<=0 ){return ResultAjax.fail(-1,"参数有误!");}Userinfo userinfo = SessionUtils.getUser(request);if (userinfo == null){return ResultAjax.fail(-2,"请先登录!");}Articleinfo articleinfo = articleService.getArticleByIdAndUid(aid,userinfo.getId())return ResultAjax.success(articleinfo);}

七、修改功能:修改查询到的文章

🍅 1、通过ajax构造请求           

进入到blog_edit.html中     

        <button onclick="doUpdate()">修改文章</button>
function doUpdate(){if(title.val().trim()==""){alert("请先输入标题!");title.focus();return false;}if(editor.getValue()==""){alert("请先输入正文!");return false;}jQuery.ajax({url:"/art/update",type:"POST",data:{"id":aid,"title":title.val(),"content":editor.getValue()},success:function(res){if(res.code==200 && res.data==1){// 修改成功alert("恭喜:修改成功!");// 跳转到我的文章管理员location.href = "myblog_list.html";}else if(res.code==-2){alert("请先的登录!");location.href = "login.html";}else{alert("抱歉:修改失败!"+res.msg);}}});}

🍅 2、处理请求

🎄 mapper层

进入到ArticleMappe中

@Update("update articleinfo set title=#{title},content=#{content} where id=#{id} and uid=#{uid}")int update(Articleinfo articleinfo);

🎄 service层

进入到ArticleService中

public int update(Articleinfo articleinfo){return articleMapper.update(articleinfo);}

🎄 controller层     

(1)参数校验

(2)获取登录用户

(3)修改文章,并且校验归属人

(4)返回结果

//    修改文章信息@RequestMapping("/update")public ResultAjax update(Articleinfo articleinfo,HttpServletRequest request){if (articleinfo==null || !StringUtils.hasLength(articleinfo.getTitle())|| !StringUtils.hasLength(articleinfo.getContent())|| articleinfo.getId() == 0){return ResultAjax.fail(-1,"非法参数!");}Userinfo userinfo = SessionUtils.getUser(request);if (userinfo == null){return ResultAjax.fail(-2,"请先登录!");}articleinfo.setUid(userinfo.getId());int result = articleService.update(articleinfo);return ResultAjax.success(result);}

八、文章详情

🍅 1、前端页面编写

进入到blog_content.html中

🎄 给定id值

    //左侧的个人信息<img id="photo" src="img/avatar.png" class="avtar" alt=""><h3 id="username"></h3><a href="http:www.github.com">github 地址</a>
        //右侧的博客信息<!-- 博客标题 --><h3 id="title"></h3><!-- 博客时间 --><div class="date">发布时间:<span id="createtime"></span>/阅读量:<span id="rcount"></span></div>

 🎄 使用ajax构造请求

        var aid = getParamValue("aid");
//初始化页面function init(){var aid = getParamValue("aid");if (aid==null || aid<=0){alert("参数有误!");return false;}jQuery.ajax({url:"/art/detail",type:"GET",data:{"aid":aid},success: function (res){if (res.code==200 && res.data!=null){var user = res.data.user;var art = res.data.art;if (user!=null){if(user.photo!=""){jQuery("#photo").art("src,user.photo");}jQuery("#username").html(user.username);jQuery("#artcount").html(user.artCount);}else{alert("抱歉:查询失败!"+reg.msg);}if(art!=null){jQuery("#title").html(art.title);jQuery("#createtime").html(art.createtime);jQuery("#rcount").html(art.rcount);initEdit(art.content);}else{alert("抱歉:查询失败!"+reg.msg)}}else{alert("抱歉,查询失败!"+res.msg);}}});}

🍅 2、处理请求

首先在userinfoVO中添加一个变量:

    private int artCount;   //用户发布的文章总数

🎄 mapper层

首先在Articleinfo中添加一条sql:根据id查询文章

@Select("select * from articleinfo where id=#{aid}")Articleinfo getDetaiById(@Param("aid") int aid);@Select("select count(*) from articleinfo where uid=#{uid}")int getArticleByUid(@Param("uid")int uid);

 然后再Userinfo中添加一条sql:根据id查询用户

@Select("select * from us erinfo where id=#{uid}")UserinfoVO getUserById(@Param("uid") int uid);

🎄 service层

ArticleService中

    public Articleinfo getDetail(int aid){return articleMapper.getDetaiById(aid);}public int getArtCountByUid(int uid){return articleMapper.getArticleByUid(uid);}

 UserService中

    public UserinfoVO getUserById(int uid){return userMapper.getUserById(uid);}

🎄 controller层 

(1)参数校验

(2)查询文章详情 

(3)根据uid查询用户的详情

(4)根据uid查询用户发表的总文章数

(5)组装数据

(6)返回结果给前端

首先创建一个线程池

使用ThreadPoolExecutor来构造线程池,该方法其实和JDK中的ThreadPool区别就在于,ThreadPoolExecutor式通过参数的方式去设置,而ThreadPool是通过构造方法,ThreadPoolExecutor中的方式更加直观简单。

ThreadPool然后将其注入依赖

    @Autowiredprivate ThreadPoolTaskExecutor taskExecutor;

 处理请求:

先注入依赖:

    @Autowiredprivate UserService userService;

 使用多线程并发编程就可以很快的查询到对应的文章详情了。

//查询文章详情页@RequestMapping("/detail")public ResultAjax detail(Integer aid) throws ExecutionException, InterruptedException {if(aid==null || aid<=0){return ResultAjax.fail(-1,"非法参数");}Articleinfo articleinfo = articleService.getDetail(aid);if (articleinfo == null || articleinfo.getId() <= 0){return ResultAjax.fail(-1,"非法参数!");}//根据uid查询用户的详情FutureTask<UserinfoVO> userTask = new FutureTask(()->{return userService.getUserById(articleinfo.getUid());});taskExecutor.submit(userTask);//根据uid查询用户发表的文章数FutureTask<Integer> artCountTask = new FutureTask<>(()->{return articleService.getArtCountByUid(articleinfo.getUid());});taskExecutor.submit(artCountTask);//等待任务(线程池)执行完UserinfoVO userinfoVO = userTask.get();int artCount = artCountTask.get();userinfoVO.setArtCount(artCount);//数据组装HashMap<String,Object> result = new HashMap<>();result.put("user",userinfoVO);result.put("art",articleinfo);return ResultAjax.success(result);}

九、阅读量设置

🍅 使用ajax构造请求

 //访问量+1function increamentRCount(){if (aid==null || aid<=0 ){return false;}jQuery.ajax({url:"/art/increment_rcount",type:"POST",data:{"aid":aid},success:function(res){}});}increamentRCount();

🍅 处理请求

🎄 mapper层

    @Update("update articleinfo set rcount=rcount+1 where id=#{aid}")int incrementRCount(@Param("aid") int aid);

🎄 service层

    public int incrementRCount(int aid){return articleMapper.incrementRCount(aid);}

🎄 controller层 

(1)校验参数

(2)更改数据库

(3)返回结果

 @RequestMapping("/increment_rcount")public ResultAjax incrementRCount(Integer aid){if (aid==null || aid<=0){return ResultAjax.fail(-1,"参数有误!");}int result = articleService.incrementRCount(aid);return ResultAjax.success(result);}

 十、分页处理

核心参数:

        (1)页码(当前在第几页)

        (2)每页显示的最大条数(前端灵活的控制分页功能)

后端分页返回:

        (1)当前页面的文章列表

        (2)总共有多少页:根据博客总条数/每一页显示条数的结果,向上取整(比如3.3333             取为4)

🍅 1、前端处理

首先将对应的js引入进,来根据总条数每页显示条数(向上取整

添加一个id属性:主要是为了构造出每一条博客的div出来

<!-- 每一篇博客包含标题, 摘要, 时间 -->    <div id="artListDiv"></div>

 然后初始化数据:

        (1)得到url中的分页参数

        (2)qing求后端接口

        (3)将结果返回给用户

var psize = 2; // 每页显示条数var pindex = 1; // 页码var totalpage = 1; // 总共有多少页// 初始化数据function init(){// 1.处理分页参数psize = getParamValue("psize");if(psize==null){psize = 2; // 每页显示条数}pindex = getParamValue("pindex");if(pindex==null){pindex = 1; // 页码}jQuery("#pindex").html(pindex);// 2.请求后端接口jQuery.ajax({url:"/art/getlistbypage",type:"GET",data:{"pindex":pindex,"psize":psize},success:function(res){// 3.将结果展示给用户if(res.code==200 && res.data!=null){var createHtml = "";if(res.data.list!=null && res.data.list.length>0){// 有文章totalpage = res.data.size;jQuery("#pszie").html(totalpage);var artlist = res.data.list;for(var i=0;i<artlist.length;i++){var art = artlist[i]; // 文章对象createHtml += '<div class="blog" >';createHtml += '<div class="title">'+art.title+'</div>';createHtml += '<div class="date">'+art.createtime+'</div>';createHtml += '<div class="desc">'+art.content+'</div>';createHtml += '<a href="blog_content.html?aid='+art.id+'" class="detail">查看全文 &gt;&gt;</a>';createHtml += '</div>';}}else{// 暂无文章createHtml += '<h3 style="margin-top:20px;margin-left:20px;">暂无文章!</h3>';}jQuery("#artListDiv").html(createHtml);}else{alert("抱歉:查询失败!"+res.msg);}}});}init();//点击首页function doFirst(){if (pindex<=1){alert("已经在首页了,无需跳转");return false;}location.href = "blog_list.html";}//跳转到末页function doLast(){if (pindex>=totalpage){alert("已经在末页了,无需跳转!");return false;}location.href="blog_list.html?pindex="+totalpage;}//点击上一页function doBefore(){if (pindex<=1){alert("已经在首页了,无需跳转");return false;}location.href="blog_list.html?pindex="+(parseInt(pindex)-1);}//点击下一页function doNext(){if (pindex>=totalpage){alert("已经在末页了,无需跳转!");return false;}location.href="blog_list.html?pindex="+(parseInt(pindex)+1);}

🍅 2、后端处理

推导到分页公式:每页显示两条数据

每次只有偏移量offset变了

# 第一页
mysql> select * from articleinfo order by id limit 2 offset 0;# 第三页
mysql> select * from articleinfo order by id limit 2 offset 2;# 第四页
mysql> select * from articleinfo order by id limit 2 offset 2;
.....

假设每条显示条数为pageSize,页码为pageIndex

故而推到出的公式为:offset = pageSize*(pageIndex-1)

🎄 mapper层

    @Select("select * from articleinfo order by id desc limit #{psize} offset #{offset} ")public List<Articleinfo> getListByPage(@Param("psize") int psize,@Param("offset")int offset);@Select("select count(*) from articleinfo")int getCount();

🎄 service层

   public List<Articleinfo> getListByPage(int psize,int offset){return articleMapper.getListByPage(psize, offset);}

🎄 controller层 

        (1)加工矫正

        (2)并发进行文章列表和总页数的查询

        (3)组装数据

        (4)将结果返回给前端

   @RequestMapping("/getlistbypage")public ResultAjax getListByPage(Integer pindex,Integer psize) throws ExecutionException, InterruptedException {if (pindex == null || pindex < 1){pindex = 1;}if (psize==null || psize<1){psize = 2;}//查询分页列表数据:Integer finalPsize = psize;Integer finalPindex = pindex;FutureTask<List<Articleinfo>> listTask = new FutureTask<>(()->{int finalOffset = finalPsize *(finalPindex -1);return articleService.getListByPage(finalPsize,finalOffset);}) ;//查询总页数FutureTask<Integer> sizeTask = new FutureTask<>(()->{int totalCount = articleService.getCount();double sizeTemp = (totalCount * 1.0) / (finalPsize * 1.0);return (int) Math.ceil(sizeTemp);});taskExecutor.submit(listTask);taskExecutor.submit(sizeTask);List<Articleinfo> list = listTask.get();int size = sizeTask.get();HashMap<String,Object> map = new HashMap<>();map.put("list",list);map.put("size",size);return ResultAjax.success(map);}

十一、密码加盐

先修改数据库中的字段:

mysql> alter table userinfo modify password varchar(65) not null;

🍅 1、定义加密规则

加密流程: 

使用加盐算法,也就是使用一个不重复随机的盐值+密码,得到一个无规律的密码                 (1)生成一个盐值

(2)(根据盐值 + 固定密码)进行加密 -> md5(盐值 + 密码)= 最终密码

(3)将[盐值]+ [分隔符$] + 最终密码保存到数据库中 

验证密码流程:

(1)得到盐值

(2)md5(盐值+待验证密码)->  最终待验证的密码

(3)对比最终待验证的密码和数据中的最终密码是否相同-> 相同密码正确

        

创建一个加密解密的类:                                  

 

 

public class PasswordUtils {//加盐加密public static String encrypt(String password){String salt = UUID.randomUUID().toString().replace("-","");String finalPassword = DigestUtils.md5DigestAsHex((salt+password).getBytes(StandardCharsets.UTF_8));return salt+"$"+finalPassword;}//待验证密码public static boolean decrypt(String password,String dbPassword){if (!StringUtils.hasLength(password) || !StringUtils.hasLength(dbPassword) ||dbPassword.length() != 65){return false;}String[] dbPasswordArray = dbPassword.split("$");if (dbPasswordArray.length!=2){return false;}String salt = dbPasswordArray[0];String dbFinalPassword = dbPasswordArray[1];String finalPassword = DigestUtils.md5DigestAsHex((salt+password).getBytes(StandardCharsets.UTF_8));if (finalPassword.equals(dbFinalPassword)){return true;}return false;}
}

🍅 2、修改UserController代码

reg()方法中添加以下代码:

        userinfo.setPassword(PasswordUtils.encrypt(userinfo.getPassword()));

 在login()方法中添加以下代码

//使用对象中的密码和用户输入的密码进行比较if (!PasswordUtils.decrypt(userinfoVO.getPassword(),userinfo.getPassword())){return ResultAjax.fail(-2,"用户名或者密码错误!");}

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

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

相关文章

RabbitMq-1基础概念

RabbitMq-----分布式中的一种通信手段 1. MQ的基本概念&#xff08;message queue,消息队列&#xff09; mq:消息队列&#xff0c;存储消息的中间件 分布式系统通信的两种方式&#xff1a;直接远程调用&#xff0c;借助第三方完成间接通信 消息的发送方是生产者&#xff0c…

动物IT

动物是地球上最丰富和多样化的生物群体之一。它们包括鱼类、鸟类、爬行动物、两栖动物和哺乳动物等各种类型。动物在地球上有着不同的生态角色和生活习性。 动物对于维持生态平衡和生态系统的稳定性至关重要。它们在食物链中扮演着重要的角色&#xff0c;通过捕食和被捕食来保…

CentOS6上安装MySQL8与Nginx开机自启

背景 临时在一台华为云的 CentOS6 上安装部署一个业务系统&#xff0c;这里记录下 MySQL 8 与 Nginx 的安装过程中遇到的问题。 CentOS6上安装MySQL8 # 下载 wget http://repo.mysql.com/yum/mysql-8.0-community/el/6/x86_64/mysql-community-common-8.0.19-1.el6.x86_64.r…

第一个ArkTS项目实践-鸿蒙ArkTS

第一个ArkTS项目实践-ArkTS 第一个ArkTS项目实践-ArkTS自定义组件的组成配置属性与布局配置属性布局 改变组件状态循环渲染列表数据代码ToDoItem组件ToDoList页面 效果参考资料 第一个ArkTS项目实践-ArkTS 本篇文章是官网上视频对ArkTS开发实践的第一个视频&#xff0c;主要是引…

通过案例学习pandas计算相关系数

pandas计算相关系数 在数据分析和统计学中&#xff0c;相关系数是一种用于衡量两个变量之间关系强度的统计指标。它可以帮助我们了解两个变量之间的线性关系强度和方向。 Pandas是一个强大的Python库&#xff0c;提供了许多用于数据分析和处理的功能。在本文中&#xff0c;我…

利用POM完成脚本分离实现企业级自动化(POM设计模式+页面的框架封装+测试报告截图)

利用POM完成脚本分离实现企业级自动化&#xff08;POM设计模式页面的框架封装测试报告截图&#xff09; 项目-测试-手工测试 项目-测试-手工测试 1.了解需求&#xff1b; 2.编写测试用例&#xff08;开始&#xff09;——功能测试组会去做的事情 3.执行测试用例——发送测试报…

【ES5和ES6】数组遍历的各种方法集合

一、ES5的方法 1.for循环 let arr [1, 2, 3] for (let i 0; i < arr.length; i) {console.log(arr[i]) } // 1 // 2 // 32.forEach() 特点&#xff1a; 没有返回值&#xff0c;只是针对每个元素调用func三个参数&#xff1a;item, index, arr &#xff1b;当前项&#…

Android 9.0 Vold挂载流程解析(上)

前言 我们分2篇文章来介绍Android 9.0中存储卡的挂载流程&#xff0c;本篇文章先介绍总体的挂载模块、Vold进程的入口main函数的详细分析&#xff0c;有了这些基础知识&#xff0c;下一篇中我们再详细介绍收到驱动层消息是怎么挂载和卸载存储卡的&#xff0c;还有framework层如…

vue实现穿梭框,ctrl多选,shift多选

效果图 代码 <template><div class"container"><!--左侧--><div><div class"title">{{ titles[0] }}</div><div class"layerContainer"><div v-for"item in leftLayerArray":key"…

实验三 nfs 服务器环境搭建

nfs 服务器环境搭建 nfs&#xff08;Network File System&#xff09;即网络文件系统&#xff0c;其基于UDP/IP 使用nfs能够在不同计算机之间通过网络进行文件共享&#xff0c;能使使用 者访问网络上其它计算机中的文件就像在访问自己的计算机一样。 【实验目的】 掌握 nfs 环…

Redis专题-秒杀

Redis专题-并发/秒杀 开局一张图&#xff0c;内容全靠“编”。 昨天晚上在群友里看到有人在讨论库存并发的问题&#xff0c;看到这里我就决定写一篇关于redis秒杀的文章。 1、理论部分 我们看看一般我们库存是怎么出问题的 其实redis提供了两种解决方案&#xff1a;加锁和原子操…

空洞卷积学习笔记

文章目录 1. 扩张卷积的提出2. 理解的难点 本片博客的主题思路来自于这篇文章——如何理解Dilated Convolutions(空洞卷积)&#xff0c;但是作者似乎是很久之前写的&#xff0c;文字的排版很混乱&#xff0c;自己来写一个新的。 1. 扩张卷积的提出 Multi-Scale Context Aggre…

JavaWeb_LeadNews_Day6-Kafka

JavaWeb_LeadNews_Day6-Kafka Kafka概述安装配置kafka入门kafka高可用方案kafka详解生产者同步异步发送消息生产者参数配置消费者同步异步提交偏移量 SpringBoot集成kafka 自媒体文章上下架实现思路具体实现 来源Gitee Kafka 概述 对比 选择 介绍 producer: 发布消息的对象称…

计算机视觉之三维重建(一)(摄像机几何)

针孔摄像机 添加屏障&#xff1a; 使用针孔(o光圈针孔摄像机中心)&#xff0c;实现现实与成像一对一映射&#xff0c;减少模糊。其中针孔与像平面的距离为f(焦距)&#xff1b;虚拟像平面位于针孔与真实物体之间&#xff0c;与像平面互为倒立关系。位置映射&#xff1a;利用相似…

【王道-进程与线程】

#pic_center R 1 R_1 R1​ R 2 R^2 R2 目录 知识框架No.0 引言No.1 进程的概念、组成、特征一、进程的概念二、进程的组成1、PCB进程控制块2、程序段/数据段 三、程序是如何运行的&#xff1f;四、进程的特征五、总结 No.2 进程的状态转换和组织一、进程的状态1、创建态、就绪态…

听GPT 讲Prometheus源代码--discovery

Prometheus是一个开源的系统监控和警报工具包&#xff0c;以下是Prometheus源代码中一些主要的文件夹及其作用&#xff1a; cmd/&#xff1a;这个目录包含了Prometheus主要的命令行工具&#xff0c;如prometheus/&#xff0c;promtool/等。每个子目录都代表一个可执行的命令行应…

常见前端基础面试题(HTML,CSS,JS)(三)

JS 中如何进行数据类型的转换&#xff1f; 类型转换可以分为两种&#xff0c;隐性转换和显性转换 显性转换 主要分为三大类&#xff1a;数值类型、字符串类型、布尔类型 三大类的原始类型值的转换规则我就不一一列举了 数值类型&#xff08;引用类型转换&#xff09; Numbe…

我和 TiDB 的故事 | 远近高低各不同

作者&#xff1a; ShawnYan 原文来源&#xff1a; https://tidb.net/blog/b41a02e6 Hi, TiDB, Again! 书接上回&#xff0c; 《我和 TiDB 的故事 | 横看成岭侧成峰》 &#xff0c;一年时光如白驹过隙&#xff0c;这一年我好似在 TiDB 上投入的时间总量不是很多&#xff0…

回归预测 | MATLAB实现CSO-SVM布谷鸟优化算法优化支持向量机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现CSO-SVM布谷鸟优化算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现CSO-SVM布谷鸟优化算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效果一…

redis 存储结构原理 2

咱们接着上一部分来进行分享&#xff0c;我们可以在如下地址下载 redis 的源码&#xff1a; https://redis.io/download 此处我下载的是 redis-6.2.5 版本的&#xff0c;xdm 可以直接下载上图中的 **redis-6.2.6 **版本&#xff0c; redis 中 hash 表的数据结构 redis hash …